1、 游戏基本介绍

1.1 游戏介绍

  • 本游戏主题是探索收集类的 RPG游戏,对于剧情任务没有太多的设计,是一个自由探索度较高的游戏。

  • 人物可通过在地图上的自由探索获得宝箱,在野外刷怪获得经验进行升级,获取相应的奖励,游戏特点是在玩家被击败之后将会失去所有的拾取物品,但是会保留当前的hero等级。

  • 采用的程序设计语言是 JavaScript 脚本语言,适用于和引擎进行交互,利用 cocos creator 游戏引擎进行游戏外观的整体实现,内层逻辑由编写的脚本进行控制。

1.2 游戏思想

  • 主角设定是 hero ,游戏版图是 迷宫式 的大地图,通过在一个地图上 探索收集 装备,打怪 获得经验升级;NPC的设定是静态的,当hero接近时便会与之进行交谈,获取迷宫的信息或普通的交谈对话;
  • monsterNPC 有一样的规则设定,但是与hero的唯一交互就是战斗。
  • 当hero接近游戏地图的传送点时会进行游戏的传送,但是会实现进行hero等级的检测,如果没有满足相应的等级要求,则不能进行地图的传送,也就是所谓的通关。
  • 地图的周围有墙体限定,hero不能越过地图边界,防止出现穿模现象。
  • 在通过某些特定的场景或者是特殊的monster时,会开启场景的音效设置,包括人物的释放技能,与NPC的交互等等。

2、 游戏规划

  • 第一步:在确定游戏的整个流程走向之后,便开始针对hero,monster,NPC等进行属性、行为设计(预先规划可能会与后面的实现有些许的冲突,最终的效果由后期完善的结果为准),属性设计完成之后便开始寻找相关的素材贴图。

  • 第二步:对游戏素材进行一个处理,将一类型之类的素材进行打包防止,防止内部资源访问错乱。确定主要人物的行走、攻击动作,各种UI界面的贴图,按键的响应动画,敌人的动作,制作地图即游戏背景,还有设计与NPC有关的剧情设计,寻找合适的背景音乐,音效等等,游戏的大部分素材此阶段完成准备,后期需要的特定素材再进行单独的处理。图片的预处理由 ShoeBoxTexturePackerGUI 等图片处理工具进行,包括动态动作的拆分序列、重新打包成合集图片等等。

  • 第三步:搭建游戏主场景,制作相关的人物预制体,包括技能、怪物等动画制作。

  • 第四步:按照游戏设计规划,进行游戏脚本的编写,逐步实现整个游戏的制作。

  • 第五步:游戏整体测试,完善逻辑,修复bug,打包发布。

3、 游戏功能设计

 3.1 地图设计

  由于是探索式的收集游戏,地图采取大图的方式,视图窗口随着hero的移动而在整个大背景地图上进行移动。避免 游戏穿模 的现象发生,在 房屋城墙树木 等应具有实体的物体上添加碰撞检测,全部设计为静态的floor层级,当与hero的层级对象进行碰撞时,将静止hero进行任何方向的位置偏移,也就限制hero的活动范围。当hero满足一定的条件后会开启下一个地图的通道,可实现场景的切换,地图间的设定规格一致。

游戏地图

 3.2 界面设计

  游戏涉及的UI界面不多,主要是绑定在hero身上的一个大界面以及一个显示当前hero所拥有的物品的背包界面,代表hero拥有的 金币钻石的UIhero等级血量蓝量名称的UI背包 及设置界面的按钮UI,以及各类的 游戏物品 。用户刚进入游戏时会在主界面进行停留,根据用户的选择而进行游戏的具体开展。
游戏界面

登陆界面

 3.3 交互设计

  整个游戏的交互系统都是由hero进行触发的,hero靠近宝箱时会随机产生一个宝物被hero所拾取,同时会获得相应的金币和钻石。靠近游戏的NPC时会进行相应的对话交谈,遇见monster时可以选择交战或者逃 走,战胜则可获得hero升级所需的经验,有几率掉落稀有的物品。

NPC 交互

 3.4 角色设计

  作为一个RPG游戏,首先的需求便是玩家操控的角色,在此游戏中为一个hero人物,玩家操作此角色在游戏中任意探索。

  玩家对应一个角色,开始游戏,随着后面关卡的发展,会有不同敌人出现,玩家扮演的hero角色对抗monster,玩家可根据游戏规则进行相应的攻击玩法。

  给每个角色的属性:bloodBase(基础血量),bloodTime(实时血量), blueBase (基础蓝量),blueTime(实时蓝量),experice(经验值),grade (等级),attack(攻击力),property(随机属性增强),goal(金币),diamond(钻石)。这些属性初始值决定这个角色的生命值魔法值经验值,通过对抗每个属性值会减少,生命值也会降低。如果生命值为零,则说明游戏失败。

  HP初始值为 100,BP初始值为 100 ,EXP初始值为 0,需要玩家通过游戏来获取,游戏中途会掉落宝箱,有可能会有宝物,或其他道具来提升属性,战胜monster也会获得一些奖励。

  • 每个属性初始值:

    初始属性基础血量实时血量基础蓝量实时蓝量经验值
    等级*100100等级*1001000
    等级金币钻石攻击属性
    100201

  说明:

  初始值:HP=100,BP=100,EXP=0

  每升一级提升1个属性点,属性点随机增强hero的各项属性技能,按照0-0.5之间的偏移变化,游戏为自由随机机制,属性会随机分配,同样的条件下可能会产生不一样的结果,玩家可自行探索。

hero

 3.5 敌人设计

  其次需要与主角作战的敌人,在此游戏中为世界各地的怪物,包括鸡怪、鸭怪、狗怪、猪怪以及大龙等。

  敌人其实和玩家操作的角色相同,只不过随着hero的升级,我们遇到的属性更加强大,游戏难度会随之加大。玩家需要根据实际情况进行对战,合理攻击并击败敌人夺取胜利。

  给每个角色的属性:bloodBase(基础血量),grade(等级),property(随机属性增强)。这些属性初始值决定这个角色的生命值。生命初始值为100,通过对抗属性值会减少,生命值也会降低。如果怪物生命值为零,说明玩家胜利 ,敌人的生命值一般是不可以增加的,但存在特殊的monster会存在增加生命的技能属性,而玩家可以使用道具来恢复生命。

  • 每个属性初始值

    角色/属性力量敏捷血量智慧
    200.210025
    450.210040
    700.210060
    800.210075
    900.4100095

dragon

 3.6 装备设计

  为了增加游戏性,还需要装备系统,应分为不同品质,使玩家乐意花时间去刷装备,增加他们的游戏时间。

  游戏装备应该有服装,玩家可以使用获得的金币,去购买一些更好看的服饰,装扮物品,来提升游戏体验。

  还有道具,玩家可以在游戏开始前,前往商店,使用金币,购买一些能够提升技能的装备,让自己更加强大对抗敌人,还可以购买一些让自己恢复的药品。

  宝箱:玩家可以购买宝箱,然后打开,里面会有随机物品出现,有可能是钱币,一份,道具,装扮,经验卡,复活卡,等东西。针对不同属性的恢复药品。

  玩家所有的东西都可在背包中查看。

bag

4、 游戏程序设计

 4.1 HeroControl.js

游戏的所有线索由hero进行推动,也就是控制hero的脚本控制整个游戏的走向,其他的脚本起到丰富游戏的作用。Hero有一个全局属性目录,包括背包属性、物品属性等,这一系列的属性归整个游戏所共有,可以方便数据的更新处理。

var box = require("BoxControl");

cc.Class({
    extends: cc.Component,
    
    properties: {
        //  播放主键
        m_animation : cc.Animation,
        m_sprite : [cc.Sprite],
    },
    //  游戏加载时的函数
    onLoad: function () {
        //  当前hero的移动方向
        this.move = 0;
        //  当前hero的技能标记
        this.kill;
        //  英雄等级标签
        var nodeGrade = cc.find("Canvas/Main/Hero/name/grade");
        this.gradeString = nodeGrade.getComponent(cc.Label);
        this.gradeString.string = "等级:" + hero.grade;
        //  注册按钮事件
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
        //  hero静止
        this.m_animation.play("3");
        //  获取当前的经验条
        this.experice = cc.find('Canvas/Main/Hero/Experiencebar/Time');
        // 记载金币钻石
        this.heroDiamondChange();
        //  获取本地的技能预制
        this.bone = cc.loader.loadRes("Prefab/bone", cc.Prefab, (err, prefab) => {
            //  加载错误则报错
            if (err) {
                console.error(err);
                return;
            }
            this.newMyPrefab = cc.instantiate(prefab);
            
        });
    },
    //  游戏的帧处理 控制hero的移动
    update: function (dt) {
        this.bloodDetection();
        this.actionJudge();
        if(this.move == 1){
            this.node.x += speed;
        }
        else if(this.move == 2){
            this.node.x += -speed;
        }
        else if(this.move == 3){
            this.node.y += speed;
        }
        else if(this.move == 4){
            this.node.y +=  -speed;
        }
    },
    //  设置代表金币和钻石的数量
    heroDiamondChange: function() {
        //  获取金币标签父节点
        var nodegoal = cc.find("Canvas/Main/Hero/buttongoal/New Label");
        //  取得金币标签并进行数量设置
        var goal = nodegoal.getComponent(cc.Label);
        goal.string = hero.goal;
        //  获取钻石标签父节点
        var nodediamond = cc.find("Canvas/Main/Hero/buttondiamond/New Label");
        //  取得钻石标签并进行数量设置
        var diamond = nodediamond.getComponent(cc.Label);
        diamond.string = hero.diamond;
        //  hero经验条的变换
        this.expericeChange();
    },
    //  更改播放的动画
    animationChange: function(data){
        if(this.actionJudge()){
            //  右移动画
            if(this.move == 1)
                this.m_animation.play("runr");
            //  左移动画
            else if(this.move == 2)
                this.m_animation.play("runl");
            //  上移动画
            else if(this.move == 3)
                this.m_animation.play("runu");
            //  下移动画
            else if(this.move == 4){
                this.m_animation.play("rund");
            }  
            //  攻击动画
            else if(this.move == 5){
                this.playingKill();
            }
        }
    },
    //  按键按下时的响应函数
    onKeyDown:function(event){
       switch(event.keyCode){
            //  按下D键      
            case 68:{
                this.move = 1;
            }
                break;
            //  按下A键
            case 65:{
                this.move = 2;
            }
                break;
            //  按下W键
            case 87:
                this.move = 3;
                break;
            //  按下S键
            case 83:
                this.move = 4;
                break;
            //  按下K键
            case 75:
                pickUp = 1;
                break;
            //  按下H键
            case 72:
                this.move = 5;
                this.kill = 1;
            break;
            case 74:
                this.move = 6;
            break;
        }
        this.animationChange("");
    },
    //  按键弹起时的响应函数
    onKeyUp: function(event){
       switch(event.keyCode){
           case 68:
           break;

           case 65:
           break;

           case 87:
           break;

           case 83:
           break;

           case 75:
           pickUp = 0;
           break;
       }
       this.move = 0;
       this.heroDiamondChange();
    },

    //  检测是否可以进行动画的播放
    actionJudge: function() {
        if(this.m_animation.getAnimationState("kill_swing")._isPlaying){
            speed = 0;
            return false;
        }
        else{
            if(this.node.getChildByName("bone") != null){
                this.newMyPrefab.removeFromParent();
                this.animationChange();
                speed = 1.5;
            }  
            return true;
        }
    },

    //  hero血条的实时响应方法
    bloodDetection: function() {
        //  人物血条制作
        this.m_sprite[0].fillRange = hero.bloodTime / hero.bloodBase * hero.grade;
        this.m_sprite[1].fillRange = hero.blueTime / hero.blueBase * hero.grade;       
    },

    //  hero经验条的更新检测
    expericeChange: function() {
        //  如果经验条满了
        if(hero.experice >= 100 * hero.grade){
            hero.experice -= 100 * hero.grade;
            hero.grade += 1;
            this.gradeString.string = "等级:" + hero.grade;
            expericeChange();
        }
        //  如果经验条没满
        else{
            this.experice.scaleX = hero.experice / (100 * hero.grade);
        }
    },

    //  技能播放
    playingKill(){
        if(this.kill == 1){
            this.m_animation.play("kill_swing");
            this.node.addChild(this.newMyPrefab);
            this.newMyPrefab.setPosition(-200, 0);
        }
    }
});

 4.2 BoxControl.js

控制游戏的一切界面交互,例如游戏界面的跳转、背包界面的打开、hero物品的生成等等。

cc.Class({
    extends: cc.Component,
    properties: {
        packet: {
            default: null,
            type: cc.Node,
            count : Boolean,
            display : Boolean,
        },
        monsterbame: {
            default: null,
            type: cc.Node,
        },
    },
    
    //  场景初始化
    onLoad: function () {
        //  monster的血条显示
        this.sign = true;
        //  背包的点击状态
        this.packet.count = true;
        //  背包显示情况
        this.packet.display = true;
        //  怪物血条的刷新频率
        this.loadMonsterBloodPassTime = 0.2;
        this.loadMonsterBloodNowTime = 0;
        //  怪物血条和名字控件
        this.monstername = this.monsterbame.getChildByName("name").getComponent(cc.Label);
        this.monsterblood = this.monsterbame.getChildByName("ui").getChildByName("blood").getComponent(cc.Sprite);
        //  注册按钮事件
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);

    },

    update: function (dt) {
        //  累计刷新时间
        this.loadMonsterBloodNowTime += dt;
        if(this.loadMonsterBloodNowTime > this.loadMonsterBloodPassTime){
            this.loadMonsterBloodNowTime = 0;
            if(isLoad){ 
                this.loadMonsterBlood();
                this.sign = false;
            }
            else{
                this.removeMonsterBlood();
                this.sign = true;
            }
        }
        
    },
    //  按键按下时的响应函数
    onKeyDown:function(event){
        switch(event.keyCode){    
            //  按下 B 键  
            case 66:
            this.bagClick();
                break;
         }
     },

    //  背包点击方法
    bagClick: function(data){
        if(this.packet.count){
            //  将背包显示到界面
            this.packet.setPosition(0, 0);
            this.packet.count = false;
            speed = 0;
            this.loadGoods();
        }
        else if (!this.packet.count){
            //  将背包移除界面
            this.packet.setPosition(1000, 0);
            this.packet.count = true;
            this.packet.display = true;
            var node = cc.find('Canvas/Main/Hero/package');
            //  移除所有物品
            node.removeAllChildren();
            speed = 1.5;
        }
    },

    //  背包物品加载
    loadGoods: function() {
        var node = cc.find('Canvas/Main/Hero/package');
        node.removeAllChildren();
        if(this.packet.display){
            cc.loader.loadRes('Interface/button1',cc.SpriteAtlas, (err, atlas) => {
            let starNode = new cc.Node();
            //  调用新建的node的addComponent函数,会返回一个sprite的对象
            const sprite=starNode.addComponent(cc.Sprite)
            //  给sprite的spriteFrame属性 赋值
            sprite.spriteFrame=atlas.getSpriteFrame("slice85_85");
            //  把新的节点追加到node节点去。就是脚本挂载的节点
            starNode.parent = this.packet;
       })
        }
        bagNum = 0;
        cc.loader.loadRes("Food/Foods", cc.SpriteAtlas, (err, atlas) => {
            //  加载错误则报错
            if (err) {
                console.error(err);
                return;
            }
            //  创建一个使用图片资源的新节点对象
            for (let index = 0; index < bag.length; index++) {
                if(bag[index].num > 0){
                    //  创建一个新节点
                    let starNode = new cc.Node(); 
                    starNode.name = bag[index].name;
                    //  创建物品位置
                    starNode.setPosition(-180 + bagNum * 60, 120); 
                    //  增加精灵组件
                    let starSprite = starNode.addComponent(cc.Sprite); 
                    //  设置精灵组件图片资源
                    starSprite.spriteFrame = atlas.getSpriteFrame(bag[index].name); 
                    let button = starNode.addComponent(cc.Button);
                    button.name = bag[index].name;
                    button.node.on('click', this.callback, this);
                    starNode.parent = this.packet;
                    bagNum++;
                }
            }
        });  
    },

    //  场景更换
    changeGame: function(target, data){
    },

    //  背包物品点击回调
    callback: function(event) {
        //  点击之后物品数量减少
        cc.log(event.target.name);
        //  初始化物品位置
        var index = -1;
        //  查找物品在背包中的位置
        for (var i = 0; i < bag.length; i++) {
            if (bag[i].name == event.target.name) {
                index = i;
                break;
            }
        }
        // 判断使用的物品给hero加属性
        switch (event.target.name) {
            case "bun":
                hero.bloodTime += 8;
                break;
            case "cowpea":
                hero.blueTime += 15;
                break;
            case "drumstick":
                hero.bloodTime += 20;
                break;    
            case "hot_dog":
                hero.bloodTime += 10;
                break;  
            case "hot_pot":
                hero.bloodTime += 15;
                break;
            case "noodles":
                hero.bloodTime += 12;
                break;
            case "omelet_rice":
                hero.blueTime += 20;
                break;    
            case "pepper_spray":
                hero.bloodTime += 30;
                break;
            case "sliced_bread":
                hero.bloodTime += 5;
                break;    
            case "tortoise":
                hero.blueTime += 20;
                break;   
        }
        // 超出基本血量则直接等于基本血量
        if (hero.bloodTime > hero.bloodBase) {
            hero.bloodTime = hero.bloodBase;
        }
        // 超出基本蓝量则直接等于基本蓝量
        if (hero.blueTime > hero.blueBase) {
            hero.blueTime = hero.blueBase;
        }
        //  数量减一
        bag[index].num--;
    },

    //  记载monster的血条UI
    loadMonsterBlood: function(){
        if(this.sign){
            //  monster相关信息显示
            this.monsterbame.setPosition(110,280);
            this.monstername.string = monsterDragon.name + "---" + monsterDragon.grade + "级";
            this.monstername.node.color = cc.color(255,0,0);
            this.monstername.fontSize = 15;
        }
        this.monsterblood.fillRange = monsterDragon.bloodTime / monsterDragon.bloodBase;
    },
    //  卸载monster的血条UI
    removeMonsterBlood : function(){
        if(!this.sign){
            //  将monster血条移除界面显示
            this.monsterbame.setPosition(110,400);
        }
    },
    //  save file
    fileClick: function() {
        cc.sys.localStorage.setItem("grade", hero.grade);
        cc.sys.localStorage.setItem("goal", hero.goal);
        cc.sys.localStorage.setItem("diamond", hero.diamond);
    },
});

 4.3 AllControl.js

负责存储游戏中的全部共有属性变量,例如NPC的交谈内容、游戏的帮助文档等等。

//  屏幕的移动速度也可视为hero的引动速度
window.speed = 1.5;
//  hero的整体属性
window.hero = {
    bloodBase : 100,
    bloodTime : 50,
    blueBase : 100,
    blueTime : 50,
    experice : 0,
    grade : 1,
    goal : 0,
    diamond : 0,  
};
//  hero的背包属性
window.bagNum = 0;
window.bag = [{name : "bun" , num : 0}, // 小面包加血8点
              {name : "cowpea" , num : 0}, // 缸豆加血蓝15点
              {name : "drumstick" , num : 0},// 鸡腿加血20点
              {name : "hot_dog" , num : 0},  // 热狗加血10点
              {name : "hot_pot" , num : 0},  // 火锅加血15点
              {name : "noodles" , num : 0},  // 面条加血12点
              {name : "omelet_rice" , num : 0}, // 蛋包饭加蓝20点
              {name : "pepper_spray" , num : 0},// 辣椒水加血30点
              {name : "sliced_bread" , num : 0},// 切片面包加血5点
              {name : "tortoise" , num : 0}]; // 王八汤加蓝20点

//  拾取
window.pickUp = 0;
//  商店NPC
window.message = {
    // 商店NPC
    shop : "你好,冒险者,有什么食物需要购买的么!",
    // 铁匠npc
    smithy : "你好,冒险者,有什么武器需要打造的么!",
    // 酒馆NPC
    tavern : "你好,冒险者,有什么药水需要购买的么!",
    // 杂货NPC
    variety : "你好,冒险者,有什么物品需要兑换的么!",
};
//  monster的整体属性
window.monsterDragon = {
    bloodBase : 1000,
    bloodTime : 0,
    experice : 100,
    grade : 10,
    name : "魔龙",
    attackArea : 100,
}
//  是否加载monster血条
window.isLoad = false;
//  相关的碰撞检测信息
window.tag = {
    tag0 : 0,   //  防穿模检测
    tag1 : 1,   //  宝箱
    tag2 : 2,   //  NPC
    tag3 : 3,   //  场景切换到森林
    tag4 : 4,   //  场景切换到市区
    tag5 : 5,   //  hero技能
    tag6 : 6,
    tag7 : 7,
    tag8 : 8,
    tag9 : 9,
    tag10 : 10, //  hero
}

 4.4 HitDetect.js

负责游戏的整体碰撞检测,检测 herofloorroadwall 等层级发生碰撞时的检测和动作,还存在其他的检测脚本,针对于特殊物件设定的专属碰撞检测。

cc.Class({
    extends: cc.Component,

    properties: {

    },

    onLoad: function () {
        //开启碰撞监听
        cc.director.getCollisionManager().enabled = true;
    },

    onCollisionEnter: function (other) {
        if(other.tag == 1){
            speed = 1.5;
        }
        else if(other.tag == 2){
            speed = 1.5;
        }
        else if(other.tag == 3){
            cc.director.loadScene('game2');
        }
        else if(other.tag == 4){
            cc.director.loadScene('game1');
        }
        else{
            speed = 0;
        }
    },

    // 碰撞状态中调用
    onCollisionStay(other, self) {
        if(other.tag == 1){
            speed = 1.5;
        }
        else if(other.tag == 2){
            speed = 1.5;
        }
        else{
            speed = 0.1;
        }
    },

    // 碰撞结束时调用
    onCollisionExit(other, self) {
        speed = 1.5;
    },

});

 4.5 TreasureControl.js

负责 hero宝箱 等可进行拾取的物品的碰撞的检测及相应的产生动作等。

cc.Class({
    extends: cc.Component,

    properties: {

    },

    onLoad: function () {
        //  开启碰撞监听
        cc.director.getCollisionManager().enabled = true;
        this.touch = 0;
        this.randomTreasure = parseInt(Math.random() * 5);
    },

    onCollisionEnter: function (other) {
        //  英雄与宝箱相碰撞
        if(other.tag == 10 && this.touch == 0){
            //  
            this.touch++;
            cc.loader.loadRes("Food/Foods", cc.SpriteAtlas, (err, atlas) => {
                //  加载错误则报错
                if (err) {
                    console.error(err);
                    return;
                }
                //  创建一个使用图片资源的新节点对象
                let starNode = new cc.Node(); 
                starNode.parent = this.node;
                starNode.name = "";
                //  增加精灵组件
                let starSprite = starNode.addComponent(cc.Sprite); 
                //  设置精灵组件图片资源
                starSprite.spriteFrame = atlas.getSpriteFrame(bag[this.randomTreasure].name); 
                //  添加物品的上升动作
                var move = cc.moveTo(1, 0, 40);
                starNode.runAction(move)
            }); 
        }
    },

    // 碰撞状态中调用
    onCollisionStay(other, self) {
        if(pickUp == 1){
            this.pickUp(); 
        }
    },

    // 碰撞结束时调用
    onCollisionExit(other, self) {
        ;
    },

    pickUp: function() {
        //  随机进行金币和钻石的数量添加
        if(Math.random() % 2 == 0){
            hero.goal += 10;
        }
        else{
            hero.diamond += 5;
        }
        hero.experice += 20;
        bag[this.randomTreasure].num += 1;
        this.node.removeFromParent();
        pickUp = 0;
    },

    update: function (dt) {
        
    },
});

 4.6 NpcControl.js

负责游戏中玩家与NPC的整个交互系统。

cc.Class({
    extends: cc.Component,

    properties: {
        //  hero的节点
        m_hero : {
            default : null,
            type : cc.Node,
        },
    },

    onLoad: function () {
        //  开启碰撞监听
        cc.director.getCollisionManager().enabled = true;
        //  创建NPC的对话节点
        this.textNode = new cc.Node();
        this.textNode.name = "label"; 
        this.textNode.parent = this.node;
        this.textNode.color = cc.color(255, 255, 0);
        //  创建位置
        this.textNode.setPosition(-80, 80); 
        //  增加对话节点框 文本节点
        this.textSprite = this.textNode.addComponent(cc.Sprite);
        this.starLabel = this.textSprite.addComponent(cc.Label); 
        this.starLabel.enableWrapText = true;
        this.starLabel.overflow = 3;
        this.starLabel.lineHeight = 15;
        this.starLabel.HorizontalAlign = cc.LEFT;
        this.starLabel.string = "";
        this.starLabel.fontSize = 10;
    },

    update: function (dt) {
        
    },
    //  碰撞开始时调用
    onCollisionEnter: function (other) {
        if(other.tag == 10){
            //  加载对话面板
            this.loadText();
            //  取得对话框标签并进行数量设置
            if (this.node.name == "shopnpc") {
                // 商店NPC的对话内容
                this.starLabel.string = message.shop;
            }else if (this.node.name == "smithynpc") {
                // 铁匠NPC的对话内容
                this.starLabel.string = message.smithy;
            }else if (this.node.name == "varietynpc") {
                // 杂货NPC的对话内容
                this.starLabel.string = message.variety;
            }else if (this.node.name == "tavernnpc") {
                // 酒馆NPC的对话内容
                this.starLabel.string = message.tavern;
            }
            
        }
        else{
            
        }
    },

    // 碰撞状态中调用
    onCollisionStay(other, self) {
        
    },

    // 碰撞结束时调用
    onCollisionExit(other, self) {
        this.starLabel.string = "";
        this.textSprite.spriteFrame = null;
    },

    //  加载对话面板
    loadText: function() {
        //  加载对话框背景
        cc.loader.loadRes('Interface/text', cc.SpriteFrame, (err,Frame) => {
            this.textSprite.spriteFrame = Frame;
        });
    },
});

 4.7 LoginControl.js

负责游戏登陆的界面判断,和主界面的跳转工作。

cc.Class({
    extends: cc.Component,

    properties: {
        user: {
            default: null,
            type: cc.EditBox,
        },
        password: {
            default: null,
            type: cc.EditBox,
        }
    },

    onLoad: function () {
        //  创建版本显示信息的文本框
        this.infoNode = new cc.Node();
        this.infoNode.parent = this.node;
        this.versionNode = new cc.Node();
        this.versionNode.parent = this.node;
        //  创建位置和显示颜色
        this.infoNode.setPosition(0, 245); 
        this.infoNode.color = cc.color(0, 0, 255);
        this.versionNode.setPosition(0, 185); 
        this.versionNode.color = cc.color(0, 0, 255);
        //  增加对话文本节点
        this.info = this.infoNode.addComponent(cc.Label); 
        this.version = this.versionNode.addComponent(cc.Label);
        //  设置文本内容
        this.info.string = "Magic baby";
        this.version.string = "version 1.1.0";
        //  拿到显示信息
        var node = cc.find('Canvas/loginB/hint');
        this.hint = node.getComponent(cc.Label);
    },

    login: function (params) {
        //  检测账号密码输入是否正确
        if (this.user.string == "admin" && this.password.string == "root") {
            this.hint.node.color = cc.color(0, 0, 255);
            this.hint.string = "correct";
            // 记载本地文件中的所有数据信息
            this.loadGameInfo();
            //  正确跳转游戏主界面
            cc.director.loadScene('game1');
        }else {
            //  错误提示玩家输入错误
            this.hint.node.color = cc.color(255, 0, 0);
            this.hint.string = "error";
            cc.log(cc.sys.localStorage.getItem("password"));
        }
    },
    update: function (dt) {

    },
    
    // 记载本地文件中的所有数据信息
    loadGameInfo : function() {
        // 加载本地数据
        // cc.loader.loadRes('data/hero.json', function (err, object) {
        //     if (err) {
        //         console.log(err);
        //         return;
        //     }
        //     // 读取的数据返回在object中,这是一个拥有2个元素的对象
        //     hero.grade = object.grade; 
        //     hero.goal = object.goal;   
        // });
        hero.grade = JSON.parse(cc.sys.localStorage.getItem("grade"));
        hero.goal = JSON.parse(cc.sys.localStorage.getItem("goal"));
        hero.diamond = JSON.parse(cc.sys.localStorage.getItem("diamond"));
    },
});

 4.8 MonsterControl.js

负责游戏monster的控制。

cc.Class({
    extends: cc.Component,

    properties: {
        //  hero的节点
        m_hero : {
            default : null,
            type : cc.Node,
        },
    },
    onLoad: function () {
        //开启碰撞监听
        cc.director.getCollisionManager().enabled = true;
        //  拿到monster及hero的节点信息,便于后面的交互处理
        this.hero = this.m_hero;
        this.monster = this.node;
        this.name = this.node.name;
        //  monster的面板显示范围,移动范围
        this.area = 300;
        this.moveArea = 100;
    },

    update: function (dt) {
        this.calculatePosition();
    },

    //  monster与hero的距离检测,当距离范围小于100时,monster这则可以开始进行攻击
    calculatePosition: function() {
        var mx = this.monster.x;
        var my = this.monster.y;
        var hx = this.hero.x;
        var hy = this.hero.y;
        if(Math.sqrt((mx-hx)*(mx-hx)+(my-hy)*(my-hy)) < this.area){
            isLoad = true;
        }
        else{
            isLoad = false;
        }
    },
    onCollisionEnter: function (other) {
        monsterDragon.bloodTime -= 100;
    },

    // 碰撞状态中调用
    onCollisionStay(other, self) {
        if(other.tag == 5){
            monsterDragon.bloodTime -= 2;
        }
    },

    // 碰撞结束时调用
    onCollisionExit(other, self) {
        if(monsterDragon.bloodTime <= 0){
            this.node.removeFromParent();
            isLoad = false;
            hero.experice += 90;
        }
    },
});

5、游戏操作

 5.1 运行控制

  • 点击 “登陆” 进入游戏界面。

  • 游戏开始时可以通过游戏界面的设置按钮进行游戏帮助的访问。

  • 任务界面,通过使用键盘操控主角完成一系列动作,消灭敌人,获取经验值。

  • 敌人消失获取经验值升级表示游戏挑战成功,血量和生命值 消耗为0 表示挑战失败退出游戏进行重置。

  • 点击游戏界面的设置按钮弹出退出游戏的按键就可以返回游戏的主界面中进行游戏的重新进入。(游戏没有设置数据库的支持,所以在退出游戏之后所有当前游戏产生的属性都会被清置为0)。

 5.2 操作信息

  • A、D、W、S分别为hero的左、右、上、下移动按键;

  • K键可以拾取物品;

  • J、H键为hero的技能攻击键;

  • B键可以打开人物的背包界面。

结果视频

[video(video-3OMfCVVG-1623651081648)(type-csdn)(url-https://live.csdn.net/v/embed/166627)(image-https://vedu.csdnimg.cn/87cab34fdb1f44dbb3a3e14a60c7a0ac/snapshots/f7be385c7fd444579837e71f137a62db-00005.jpg)(title-)]

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐