cocos角色和敌人行为互动脚本制作

给宝宝做一个cocos免费游戏

第一章 背景和开发框架介绍
第二章 Node树和场景制作
第三章 UI、地图和关卡文本制作
第四章 摇杆、按键和角色动画制作
第五章 敌人和AI制作
第六章 角色和敌人行为互动脚本制作
第七章 游戏打包、发布和调试

cocos角色和敌人行为互动脚本制作


前言

前面错漏百出的介绍了怎么制作地图、ai和角色,这一节顺水推舟做他们的交互。有朋友私信说啥时候可以补充下剧情跟美工,关键技术在了但是画面看起来货不对板。压力山大,有空先,后面娓娓道来,美工小姐姐抱娃去了只能雌雄同体了
道个歉,忙了一段时间,游戏项目搁置了很久。


一、角色跟地图交互

主要因为我们没有使用tiedmap制作地图,非要作死另辟蹊径,掉进了小溪里。所以要做地图阻隔功能、剧情触发、掉血处理等。酸爽求虐的感觉

(一)阻隔的实现

1.地图对象——碰到了就切线移动吧,这样实现可以的。别忘了还有一个组件叫做物理引擎,必须用上做阻隔
现在把之前地图prefab对象添加上物理引擎。
cocos角色和敌人行为互动脚本制作
勾选刚体Bullet,type选择Static固定的(毕竟是墙壁等)
cocos角色和敌人行为互动脚本制作
其他默认即可
当然,第一步是在加载地图时候记得开启物理引擎

在这里插入代码片

2.角色对象:
(1)关键位置如身体手脚可能接触的组件都添加碰撞体(也是物理组件)
注意:角色由多个物理接触点如武器 手脚等,如果不添加JOIN类物理组件,物理开启了滞后,不会跟随主node行动
join类物理组件请参考:https://blog.csdn.net/qq_43287088/article/details/107948878
当然也可以使用最简单的方法,animation动作制作时候,除了angle还要记录position,这样可以偷工减料。
cocos角色和敌人行为互动脚本制作

(二)完善地图触发

对门、*、箱子等添加代码,实现阻隔和通行切换、加载内容等,考虑互动性,加载aijs.js并把响应代码写在上面
cocos角色和敌人行为互动脚本制作
调整下canvasjs.js的loadMaoObj和Main.json
cocos角色和敌人行为互动脚本制作
cocos角色和敌人行为互动脚本制作

二、角色和AI互动

相关代码都写在ajjs.js文件上,通过reacttype判断

        switch(this.reacttype){
            case 'box':   break;
            case 'guid':  break;
            case 'dialog':break;
            case 'player':break;
            case 'enemy': break;
            case 'story': break;
            case 'loader':break;         
        }

1.load读出tab

//这里直接在ajjs.js中累加属性(jstick中已经加载菜单)
    loadEquipment:function(owner){
        switch(this.reacttype){
            case 'box':  break;
            //json-items:position = owner
            case 'guid':  break;
            case 'dialog':break;
            case 'player': //角色的装备属性
                //ui-tab 
                var eq = cc.find('Canvas').getChildByName('UI').getChildByName('itemScrollView').getChildByName('equipment');
                if(eq){
                    var eqs = eq.children;
                    if(eqs.length > 0){
                        for(var i=0;i<eqs.length;i++){
                          var ip = eqs[i].children[0]?eqs[i].children[0].getComponent('itemstab'):null;
                          if(!ip){return;}
                          this.feeldistance  = Math.round(this.feeldistance) + Math.round(ip.feeldistance);
                          this.actdistance = Math.round(this.actdistance) + Math.round(ip.actdistance);
                          this.movespeed = Math.round(this.movespeed) + Math.round(ip.movespeed);
                          this.hp = Math.round(this.hp) + Math.round(ip.hp);
                          this.lp = Math.round(this.lp) + Math.round(ip.lp);
                          this.mp = Math.round(this.mp) + Math.round(ip.mp);
                          this.at = Math.round(this.at) + Math.round(ip.at);
                          this.skill1 = ip.skill1?ip.skill1:this.skill1 ;//cd?按照按键是否active
                          this.skill2 = ip.skill2?ip.skill2:this.skill2 ;
                          this.skill3 = ip.skill3?ip.skill3:this.skill3 ;
                          this.skill4 = ip.skill4?ip.skill4:this.skill4 ;
                        //   this.skills.push( ip.skill1?ip.skill1:this.skill1 );
                        }
                    }
                }
            break;
            case 'enemy'://敌人的装备属性
                //json-items:position = owner
                if(TOOLS){
                    for(var i=0;i<TOOLS.length;i++){
                        if(TOOLS[i].owner == this.node.name){
                                          
                            if(TOOLS[i].type=='S'){ //往下走,放到空的skill栏
                                if(this.skill1 ==''){this.skill1 = TOOLS[i].name;}
                                else if(this.skill2==''){this.skill2 = TOOLS[i].name;}
                                else if(this.skill3 ==''){this.skill3 = TOOLS[i].name;}
                                else if(this.skill4 ==''){this.skill4 = TOOLS[i].name;}
                                else{}//都不为空,不执行
                                var tmp = 'name:'+TOOLS[i].name+',eff:'+TOOLS[i].eff+',at:'+TOOLS[i].value;
                                this.skills.push(tmp);
                            }                            
                            else{//消耗品也累加到属性,后面优化时候考虑使用
                                switch(TOOLS[i].eff){
                                    case 'fd':this.feeldistance  = Math.round(this.feeldistance) + Math.round(TOOLS[i].value);break;
                                    case 'ad':this.actdistance = Math.round(this.actdistance) + Math.round(TOOLS[i].value);break;
                                    case 'ms':this.movespeed = Math.round(this.movespeed) + Math.round(TOOLS[i].value);break;
                                    case 'hp':this.hp = Math.round(this.hp) + Math.round(TOOLS[i].value);break;
                                    case 'lp':this.lp = Math.round(this.lp) + Math.round(TOOLS[i].value);break;
                                    case 'mp':this.mp = Math.round(this.mp) + Math.round(TOOLS[i].vaue);break;
                                    case 'at': this.at = Math.round(this.at) + Math.round(TOOLS[i].value);break;
                                }   
                            }

                        }
                    }
                }
            break;
            case 'story':break;
            case 'loader': break;         
        }
     },

2.技能CD实现

这里直接使用random方式释放技能,当然可把技能load到array中,自己循环一下什么距离使用有mp的技能

    takeActions:function(e){
        var an = this.node.getComponent(cc.Animation);
        var anstatus = this.node.getComponent(cc.Animation).AnimationStatus;
        // if(an){an.play('att_ailhit');};
        var sk = this.sk?this.sk:[];
        if(sk.length>0){
            var r = Math.floor(Math.random()*sk.length+1); //随机无cd
            an.play(sk[r].name);
            //减血方面的打击运算,都放在碰撞上
        }
        //check free

        //important level
    },

3.伤害和扣血

在物理碰撞中实现,如果是weapon+对手,则减血

//2.物理碰撞
    onBeginContact(contact, selfCollider, otherCollider) {
        // cc.log("onBeginContact");        //碰撞触发事件
        switch(this.reacttype){
            case 'box':  
            //need key?
            break;
            case 'door':  
            //need key?
            
            break;
            case 'guid':
               if( otherCollider.node.group != 'players'){break;}
                var lv = this.node.getComponent('aijs').lv ;//get lv text
                // if(!lv){break;}
                this.node.getChildByName('RichText').active = true;    
            break;
            case 'dialog':break;
            case 'player':
                if(otherCollider.node.group == 'weapon' && otherCollider.node.parent.group == 'enemies'){
                    var pai = otherCollider.node.parent.parent.parent.getComponent('aijs')?otherCollider.node.parent.parent.parent.getComponent('aijs'):otherCollider.node.parent.parent.parent.parent.getComponent('aijs');
                    this.hp -= pai.at;    
                }
            break;
            case 'enemy':
                //1.action back:弹性系数
                //2.hp mp lp changing
                if(otherCollider.node.group == 'weapon' && otherCollider.node.parent.group == 'players'){
                    var player = cc.find('Canvas').getChildByName('mapNode').getChildByName('player');
                    var pai = player.getComponent('aijs')?player.getComponent('aijs'):player.getChildByName('body').getComponent('aijs');
                    this.hp -= pai.at;                    
                }
            break;
            case 'story':break;
            case 'loader'://加载 
                var lv = this.node.getComponent('aijs').lv ;//get lv text
                cc.loadScene(lv); 
                break;         

        }
    },

4.打倒和消灭

     goDieAndDistroy:function(e){
         if(!this.node){return;}
        var an = this.node.getComponent(cc.Animation);
        an.play('dead');
        // this.schedule(function () {
            this.node.parent.destroy();
        //   }, 0.2, 1,3);
     },

5 .最终在UPDATE方法实现简单AI

update (dt) {
        if(!this.node){return;}
        if(this.hp == 0){ 
            this.goDieAndDistroy();
            if(this.reacttype=='player'){
                var cvs = cc.find('Canvas');
                cvs.getChildByName('mapNode').acitve = false;
                cvs.getChildByName('UI').active = false;  //g over
                cvs.getChildByName('RichText').active =true ;//可以动画
              }
        }//执行一次

        else{
        //通过距离判断
        switch(this.reacttype){
            case 'guid':  break;
            case 'dialog':break;
            case 'player':break;
            case 'enemy':
                var player = this.node.parent.getChildByName('player');
                var tx = this.node.x - player.position.x;
                var pdis = this.node.position.sub(player.position);//有方向,判断<>0是无法判断向量的
                // if(this.actdistance < pdis.mag() < this.feeldistance){                      
                //       if(this.node.x > player.x){ this.node.scaleX = -1 * Math.abs(this.node.scaleX );}
                //       else{this.node.scaleX =   Math.abs(this.node.scaleX )}//turnaround
                //       if(tx < 0) {this.node.x += this.movespeed;} 
                //       else if(tx > 0){this.node.x -= this.movespeed;} //1d x轴运算即可
                         this.playAnimation('walk');
                // }
                if(this.actdistance >= pdis.mag()){
                    //take actions
                      this.takeActions();
                }
                if(pdis.mag() > this.feeldistance){
                    cc.tween(this.node).to(2,{position:this.initpos}); //原始位置
                };
                //障碍物

                break;
            case 'story':break;
        }
    }
    },

三、AI和地图

1.阻隔

使用物理引擎实现,故不需要做特殊的代码处理,原理不重复说明,记得勾选不穿透和触发方法即可

2.路线

在aijs.js的update写入逻辑:
没有打扰时候执行巡逻路线
进入距离执行追赶路线
离开后执行返回原始位置路线

总结

先到这里,后面阐述美化剧本、打包发布等内容。

上一篇:Cocos Creator 屏幕适配 (Widget,Fit Width, Fit Height,ShowAll,常用分辨率,刘海屏)


下一篇:Android Activity跳转到cocos的AppActivity 的问题