cocos creator实例--Cocos Creator实现的 大炮英雄 游戏

游戏预览

开始场景

搭建开始场景

摆放一个背景图,在背景图上添加背景地面、开始按钮、4个角色选择按钮、游戏logo。

创建游戏脚本

    1. 实现开始按钮的回调,点击开始按钮,跳转到游戏场景。跳转场景方法如下: 


cc.director.preloadScene('playScene', function () {
    cc.director.loadScene('playScene');
});

 2. 实现选择角色按钮的回调,点击某个角色时,先将其他角色设置为未选中状态,再将当前选择的角色设为选中状态,最后用cc.sys.localStorage.setItem(“key”,value);方法本地保存选择的角色类型。

    3. 在onLoad()方法中,调用cc.sys.localStorage.getItem(“key”);方法获取到本地保存的角色类型,并设置角色按钮的选中状态。

    4. 游戏中音效必不可少,点击各个按钮时,都需要播放音效,方法如下:


//播放音效
playSound : function(name, isLoop){
    cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
        if(err){
            return;
        }
        let audioID = cc.audioEngine.playEffect(clip, isLoop);
    });
},

开始场景和脚本关联

    1. 将脚本拖到start场景的属性检查器中,并将脚本中声明的属性和组件关联起来,如下图:

    

       

    2. 给开始按钮绑定回调事件,选中开始按钮,在属性检查器中,找到Button属性,将ClickEvents值改成1,表示有一个点击事件,再按照如下方式将函数和组件关联起来:

    3. 给角色按钮绑定回调,方法和给开始按钮绑定回调完全一样,只是绑定的函数不同。

游戏场景

         

游戏玩法是控制我方英雄的发炮角度,如果打中敌方英雄就得分,否则会被敌方英雄的炮弹打中,如果我方英雄血量为0则游戏结束。

搭建游戏场景

    1. 游戏主界面:包含背景,地面,我方英雄,分数文本,返回主界面按钮。

    2. 结算界面:包含遮罩层,最高得分文本,当前得分文本,重新开始按钮,返回主界面按钮。

创建游戏脚本

    gamePlay.js脚本是游戏的核心,主要方法如下:

 1. 开启物理系统:

cc.director.getPhysicsManager().enabled = true;

    2. 设置重力加速度:

cc.director.getPhysicsManager().gravity = cc.v2(0, -640);

   3. 添加触摸监听,事件分为TOUCH_START(开始)、TOUCH_MOVE(移动)、TOUCHCANCEL(取消)、TOUCH_END(结束)四个状态,方法如下:

this.node.on(cc.Node.EventType.TOUCH_START, this.onEventStart, this);this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onEventMove, this);this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onEventCancel, this);this.node.on(cc.Node.EventType.TOUCH_END, this.onEventEnd, this);

    4. 当开始触摸屏幕时,触发开始的回调onEventStart(),回调中开启定时器,每隔0.03秒角度加1,并改变炮台的角度,方法如下:

//更新炮管角度

updateGunAngle : function(){  this.shootLineImg.active = true;  this._curAngle = 0;  this.gunSchedule = function(){    if (this._curAngle < 90){      this._curAngle += 1;      this.myGunImg.angle = this._curAngle;    }  };  this.schedule(this.gunSchedule, 0.03); },

  5. 当结束触摸时,触发结束的回调onEventEnd(),回调中关闭定时器,方法如下:

//停止更新炮管stopGunAngle(){  this.unschedule(this.gunSchedule);  this.shootLineImg.active = false;},

  6. 敌人开炮,需要先调整角度再发炮,炮的角度通过敌方子弹和我方英雄的坐标可计算出来,方法如下:

//敌方开炮enemyOpenFire : function(){  //敌方子弹世界坐标  let enemyBulletPos = this._enemyNode.enemyBulletWorldPos();  //我方英雄世界坐标  let myHeroPos = this.myHeroImg.parent.convertToWorldSpaceAR(cc.v2(this.myHeroImg.position.x, this.myHeroImg.position.y + 30));
  //计算夹角  let lenX = Math.abs(enemyBulletPos.x - myHeroPos .x);  let lenY = Math.abs(enemyBulletPos.y - myHeroPos .y);  let angle = Math.atan2(lenY, lenX) * 180 / Math.PI; 
  //设置敌方小火炮的角度  this._enemyNode.setGunAngle(angle); 
  //计算炮运行的距离  let len = Math.sqrt(Math.pow(lenX, 2) + Math.pow(lenY, 2));  this._enemyNode.gunAni(len);  this.playSound("sound/enemyBullet", false);},

    7. 更换纹理方法:

//更换纹理setImgTexture : function(str, node){  cc.loader.loadRes(str, cc.SpriteFrame, function (err, spriteFrame) {    if (err) {      cc.error(err.message || err);      return;    }    node.getComponent(cc.Sprite).spriteFrame = spriteFrame;  }.bind(this));},

创建敌人脚本

敌人脚本包含敌人,柱子,敌方炮弹等信息,脚本中的主要方法有:

    1. 随机设置柱子的高度:

//调整敌方柱子高度setColumnHight : function(){  //随机获取高度  let y = Math.floor(Math.random() * -250) - 100;  this.cloumn.position = cc.v2(this._winSize.width / 2 + 100, y);},

    2. 敌人进出场的动作:

//敌人进场动作comeOnAni : function(){  this.setColumnHight();  let w = Math.floor(Math.random() * (this._winSize.width / 4));  this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(w, this.cloumn.position.y)), cc.callFunc(() =>{     this.enemyHeroImg.active = true;    this.enemyGunImg.active = true;    this.enemyAni();  }, this)));},
//敌方柱子运动enemyMove : function(){  this.enemyHeroImg.active = false;  this.enemyGunImg.active = false;  this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(-this._winSize.width / 2 - 100, this.cloumn.position.y)), cc.callFunc(() =>{    if(this.callBack){      this.callBack();  })));},

    3. 敌人开炮:

//炮运动gunAni : function(len){  let bulletPos = this.enemyBulletImg.position;  this.enemyBulletImg.runAction(cc.sequence(cc.moveTo(0.3, cc.v2(len, 0)), cc.callFunc(() =>{    if(this.hitHeroCallBack){        this.hitHeroCallBack();    }    this.enemyBulletImg.position = bulletPos;  })));},

创建碰撞脚本

碰撞脚本是给需要做碰撞检测的刚体用的,在碰撞脚本中做碰撞监听,当触发监听后,再调用相应的回调。比如我方子弹需要监听与墙壁,敌人,柱子等物体的碰撞,那么我们先给子弹绑定好碰撞组件,如下图:

    再在代码中实现碰撞的回调并保存下来,方法如下:

​​​​​​​

//碰撞监听contactFunction (selfCollider, otherCollider){  if(this.callBack){    this.callBack(selfCollider, otherCollider);  }}, 
contactCallBack (callBack){  this.callBack = callBack;},

    最后在碰撞开始的监听中调用回调,方法如下:

onBeginContact ( contact, selfCollider, otherCollider){  if(selfCollider.tag == 0 && otherCollider.tag == 0){    cc.log("onBeginContact...");  //碰撞开始    this.contactFunction(selfCollider, otherCollider);  }},

创建动画脚本

游戏中有英雄角色的等待和走路动作,敌人等待动作,如果在编辑器做动画,编辑的个数比较多,所以我的做法是通过修改纹理达到动画效果,用法是将这个脚本绑定到需要播放动画的节点上,并设置一张大图,方法如下:

    

    使用方法:​​​​​​​

playAni(nameStr, count, dt, isLoop){  this.stopAni();  this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + 0);  let array = [];  for(let i = 0; i < count; i++){    array.push(cc.delayTime(dt));    array.push(cc.callFunc(() =>{      this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + i);    }));  }       
  if(isLoop){    this.node.runAction(cc.repeatForever(cc.sequence(array)));  }  else{    this.node.runAction(cc.sequence(array));  }},

    参数分别是图片名称,图片张数,间隔时间,是否循环,调用方法:

this.shieldImg.getComponent("spriteFrameAni").playAni("shield", 4, 0.1, true);
//-------------contact.js------------------

//碰撞监听脚本
cc.Class({
    extends: cc.Component,
    properties: {

    },
    onLoad () {

    },

    onDestroy () {

    },

    onBeginContact ( contact, selfCollider, otherCollider){
        if(selfCollider.tag == 0 && otherCollider.tag == 0){
            cc.log("onBeginContact...");  //碰撞开始
            this.contactFunction(selfCollider, otherCollider);
        }
    },
  onEndContact (contact, selfCollider, otherCollider){
        //cc.log("onEndContact...");//碰撞结束 
    },
  onPreSolve(contact, selfCollider, otherCollider){
        //cc.log("onPreSolve...");//碰撞持续,接触时被调用
    },
  onPostSolve (contact, selfCollider, otherCollider){
        //cc.log("onPostSolve...");//碰撞接触更新完后调用,可以获得冲量信息
    },

    //碰撞监听
    contactFunction (selfCollider, otherCollider){
        if(this.callBack){
            this.callBack(selfCollider, otherCollider);
        }
    },

    contactCallBack (callBack){
        this.callBack = callBack;
    },

});









//-------------enemy.js------------------
cc.Class({
    extends: cc.Component,

    properties: {
        cloumnNode : cc.Node,
        cloumn : cc.Node,
        enemyGunImg : cc.Node,
        enemyBulletImg : cc.Node,
        enemyHeroImg : cc.Node,
        enemyDieParticle : cc.ParticleSystem,
    },

    onLoad: function () {
        this._winSize = cc.winSize;
        this.enemyHeroImg.active = false;
        this.enemyGunImg.active = false; 
    },

    //敌人运动
    enemyAni : function(){
        this.enemyHeroImg.getComponent("spriteFrameAni").playAni("enemy", 3, 0.1, true);
    },
    
    //调整敌方柱子高度
    setColumnHight : function(){
        //随机获取高度
        let y = Math.floor(Math.random() * -250) - 100;
        this.cloumn.position = cc.v2(this._winSize.width / 2 + 100, y);
    },

    //敌人进场动作
    comeOnAni : function(){
        this.setColumnHight();
        let w = Math.floor(Math.random() * (this._winSize.width / 4));
        
        this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(w, this.cloumn.position.y)), cc.callFunc(() =>{ 
            this.enemyHeroImg.active = true;
            this.enemyGunImg.active = true;
            this.enemyAni();
        }, this)));
    },

    //敌方柱子运动
    enemyMove : function(){
        this.enemyHeroImg.active = false;
        this.enemyGunImg.active = false;
        this.cloumn.runAction(cc.sequence(cc.moveTo(1.0, cc.v2(-this._winSize.width / 2 - 100, this.cloumn.position.y)), cc.callFunc(() =>{
            if(this.callBack){
                this.callBack();
            } 
        })));
    },

    //获取敌方子弹的世界坐标
    enemyBulletWorldPos : function(){
        let pos = this.cloumn.convertToWorldSpaceAR(cc.v2(this.enemyGunImg.position));
        return pos;
    },

    //设置炮的角度
    setGunAngle : function(angle){
        this.enemyGunImg.angle = angle;
    },

    //炮运动
    gunAni : function(len){
        let bulletPos = this.enemyBulletImg.position;
        this.enemyBulletImg.runAction(cc.sequence(cc.moveTo(0.3, cc.v2(len, 0)), cc.callFunc(() =>{
            if(this.hitHeroCallBack){
                this.hitHeroCallBack();
            }
            this.enemyBulletImg.position = bulletPos;
        })));
    },

    //敌方英雄死亡动画
    enemyDie : function(){
        this.enemyDieParticle.node.active = true;
        this.enemyDieParticle.stopSystem();
        this.enemyDieParticle.resetSystem();

        //隐藏敌方英雄
        this.enemyGunImg.active = false;
        this.enemyHeroImg.active = false;
    },

    //播放音效
    playSound : function(name, isLoop){
        cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
            if(err){
                return;
            }
            var audioID = cc.audioEngine.playEffect(clip, isLoop);
        });
    },
    
    //运动完成的回调
    finishCallBack (callBack){
        this.callBack = callBack;
    },

    //打中我方英雄后的回调
    hitHeroCallBack : function(callBack){
        this.hitHeroCallBack = callBack;
    },

    // called every frame
    update: function (dt) {

    },
});







//-------------gamePlay.js------------------

cc.Class({
    extends: cc.Component,

    properties: {
        bgImg : cc.Node,
        sunImg : cc.Node,
        moonImg : cc.Node,
        floorParent : cc.Node,
        farHouseImg0 : cc.Node,
        farHouseImg1 : cc.Node,
        nearHouseImg0 : cc.Node,
        nearHouseImg1 : cc.Node,
        farFloorImg0 : cc.Node,
        farFloorImg1 : cc.Node,
        nearFloorImg0 : cc.Node,
        nearFloorImg1 : cc.Node,
        scoreText : cc.Label,

        //我方英雄组件
        heroNode : cc.Node,
        shootLineImg : cc.Node,
        myBulletImg : cc.Node,
        myHeroImg : cc.Node,
        myGunImg : cc.Node,
        shieldImg : cc.Node,
        bloodBar : cc.ProgressBar,
        heroDieParticle : cc.ParticleSystem,

        //结束层
        endLayer : cc.Node,
        bestScoreText : cc.Label,
        allScoreText : cc.Label,

        myBulletPrefab : {
            default: [],
            type: cc.Prefab,
        },
        enemyPrefab : cc.Prefab,
    },

    onLoad: function () {
        this._winSize = cc.winSize;
        this._canShooting = true;  //是否能射击
        this._canContact = true;   //是否检测碰撞
        this._curScore = 0;  //当前得分
        this._heroBloodValue = 100;  //当前血量值

        //打开物理系统
        cc.director.getPhysicsManager().enabled = true;
        //cc.director.getPhysicsManager().debugDrawFlags = true;

        // 重力加速度的配置
        cc.director.getPhysicsManager().gravity = cc.v2(0, -640);

        //随机获取一种类型
        this.randStyle = Math.floor(Math.random() * 100) % 3; 
        cc.sys.localStorage.setItem("gunHeroBgStyle", this.randStyle);

        //角色类型
        this.heroType = parseInt(cc.sys.localStorage.getItem("gunHeroType")) || 0;

        //修改辅助线纹理
        this.setImgTexture("imageRes/line" + this.heroType, this.shootLineImg);
        
        //修改大炮纹理
        this.setImgTexture("imageRes/gun" + this.heroType, this.myGunImg);

        //游戏背景
        this.setImgTexture("bg/bgImg" + this.randStyle, this.bgImg);

        //太阳图片  
        if(this.randStyle == 2){
            this.sunImg.active = false;
            this.moonImg.active = true;
        }
        else{
            this.moonImg.active = false;
            this.sunImg.active = true;
            this.setImgTexture("imageRes/sun" + this.randStyle, this.sunImg);
        }

        //远处房子
        this.setImgTexture("imageRes/house" + this.randStyle, this.farHouseImg0);
        this.setImgTexture("imageRes/house" + this.randStyle, this.farHouseImg1);

        //近处房子
        this.setImgTexture("imageRes/houshSmall" + this.randStyle, this.nearHouseImg0);
        this.setImgTexture("imageRes/houshSmall" + this.randStyle, this.nearHouseImg1);

        //远处地面
        this.setImgTexture("imageRes/floor" + this.randStyle, this.farFloorImg0);
        this.setImgTexture("imageRes/floor" + this.randStyle, this.farFloorImg1);

        //近处地面
        this.setImgTexture("imageRes/gameFloor" + this.randStyle, this.nearFloorImg0);
        this.setImgTexture("imageRes/gameFloor" + this.randStyle, this.nearFloorImg1);
        this.nearFloorImg0.zIndex = 5;
        this.nearFloorImg1.zIndex = 5;

        //得分
        this.scoreText.string = "0";

        this.node.on(cc.Node.EventType.TOUCH_START, this.onEventStart, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onEventMove, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onEventCancel, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onEventEnd, this);

        //云动画
        this.yunAni();

        //创建敌人
        this.createEnemy();

        //我方英雄等待动作
        this.myHeroAni(false);

        //地方英雄等待动画
        this._enemyNode.enemyAni();

        //英雄身上的护盾动画
        this.shieldImg.getComponent("spriteFrameAni").playAni("shield", 4, 0.1, true);
    },

    //云动画
    yunAni : function(){
        let curWidth = -this._winSize.width / 2;
        while(curWidth < this._winSize.width / 2){
            //随机一个类型
            let t = Math.floor(Math.random() * 100) % 3;
            //随机一个高度值
            let h = Math.random() * (this._winSize.height * 1 / 6) + this._winSize.height * 2 / 8;
            curWidth = curWidth + Math.random() * 150 + 150;

            let yunNode = new cc.Node();
            let yunSp = yunNode.addComponent(cc.Sprite);
            yunNode.parent = this.floorParent;
            yunNode.position = cc.v2(curWidth, h);
            this.setImgTexture("imageRes/yun" + this.randStyle + "_" + t, yunSp);
            yunNode.runAction(cc.repeatForever(cc.sequence(cc.moveBy(1.0, cc.v2(-20, 0)), cc.callFunc(() =>{
                if(yunNode.position.x < -this._winSize.width / 2 - 100){
                    yunNode.position = cc.v2(this._winSize.width / 2 + 100, yunNode.position.y);
                }
            }))));
        }
    },

    //创建敌人
    createEnemy : function(){
        let node = cc.instantiate(this.enemyPrefab);
        node.position = cc.v2(0, -110);
        node.parent = this.floorParent;
        this._enemyNode = node.getComponent("enemy");
        this._enemyNode.comeOnAni();

        this._enemyNode.finishCallBack(()=>{
            //可检测碰撞
            this._canContact = true;
            //设置为可发炮
            this._canShooting = true;
            node.removeFromParent();
            node = null;
            this.createEnemy();
        });
        this._enemyNode.hitHeroCallBack(()=>{
            this._heroBloodValue = this._heroBloodValue - 25;
            if(this._heroBloodValue <= 0){
                this.playSound("sound/heroDie", false);
                this._heroBloodValue = 0;
                this.myHeroDie();
                //显示结算界面
                this.gameOver();
            }
            else{
                this.playSound("sound/enemyDie", false);
                this.setBloodValue();
                
                //还原炮的角度
                this.myGunImg.angle = 0;

                //设置为允许开炮
                this._canShooting = true;
                this._canContact = true;
            }
        });
    },

    //更新炮管角度
    updateGunAngle : function(){
        this.shootLineImg.active = true;
        this._curAngle = 0;
        this.gunSchedule = function(){
            if (this._curAngle < 90){
                this._curAngle += 1;
                this.myGunImg.angle = this._curAngle;
            }
        };
        this.schedule(this.gunSchedule, 0.03);
    },

    //停止更新炮管
    stopGunAngle(){
        this.unschedule(this.gunSchedule);
        this.shootLineImg.active = false;
    },

    //给自己的子弹绑定刚体
    setBulletBody : function(){
        //创建子弹
        this.bulletNode = cc.instantiate(this.myBulletPrefab[this.heroType]);
        this.bulletNode.parent = this.myGunImg;
        this.bulletNode.position = this.myBulletImg.position;
        let bulletSp = this.bulletNode.getComponent("contact");
        bulletSp.contactCallBack((selfCollider, otherCollider) => {
            if(!this._canContact){
                return;
            }
            this.playSound("sound/openFire", false);
            this._canContact = false;
            //停止子弹监听
            this.unschedule(this.bulletfun);

            let bodyGroup0 = selfCollider.node.group;
            let bodyGroup1 = otherCollider.node.group;

            //子弹打到地面
            if((bodyGroup0 == "heroBullet" && bodyGroup1 == "floor") 
            || (bodyGroup0 == "floor" && bodyGroup1 == "heroBullet")){
                this.node.runAction(cc.sequence(cc.delayTime(0.5),cc.callFunc(() =>{
                    this.bulletNode.removeFromParent();
                    this.bulletNode = null;
                    this.enemyOpenFire();
                })));
            }

            //子弹打到柱子
            if((bodyGroup0 == "heroBullet" && bodyGroup1 == "column") 
            || (bodyGroup0 == "column" && bodyGroup1 == "heroBullet")){
                this.node.runAction(cc.sequence(cc.delayTime(0.5),cc.callFunc(() =>{
                    this.bulletNode.removeFromParent();
                    this.bulletNode = null;
                    this.enemyOpenFire();
                })));
            }

            //子弹打到敌人
            if((bodyGroup0 == "heroBullet" && bodyGroup1 == "enemy") 
            || (bodyGroup0 == "enemy" && bodyGroup1 == "heroBullet")){
                this._enemyNode.enemyDie();
                this.node.runAction(cc.sequence(cc.delayTime(0.3),cc.callFunc(() =>{
                    this.bulletNode.removeFromParent();
                    this.bulletNode = null;
                    this.updateScore();
                    this.myHeroAni(true);
                    this.myHeroScaleAni();
                    this.gameBgAni();
                    this._enemyNode.enemyMove();
                })));
            }
        });
    },

    //我方英雄运动
    myHeroAni : function(isRun){
        if(isRun){
            this.myHeroImg.getComponent("spriteFrameAni").playAni("heroRun" + this.heroType + "_", 5, 0.06, true);
        }
        else{
            this.myHeroImg.getComponent("spriteFrameAni").playAni("heroWait" + this.heroType + "_", 3,  0.1, true);
        }
    },

    //我方英雄缩放效果
    myHeroScaleAni : function(){
        this.heroNode.runAction(cc.sequence(cc.scaleTo(1.0, 1.1), cc.scaleTo(1.0, 1.0)));
    },

    //背景运动
    gameBgAni : function(){
        //远处房子
        let fw = this.farHouseImg0.width;
        this.farHouseImg0.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-200, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
            if(this.farHouseImg0.position.x <= -fw - this._winSize.width / 2){
                this.farHouseImg0.position = cc.v2(this.farHouseImg1.position.x + fw, this.farHouseImg0.position.y);
            }
            this.myHeroAni(false);
        })));
        this.farHouseImg1.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-200, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
            if(this.farHouseImg1.position.x <= -fw - this._winSize.width / 2){
                this.farHouseImg1.position = cc.v2(this.farHouseImg0.position.x + fw, this.farHouseImg1.position.y);
            }
        })));

        //近处房子
        let nw = this.nearHouseImg0.width;
        this.nearHouseImg0.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-300, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
            if(this.nearHouseImg0.position.x <= -nw - this._winSize.width / 2){
                this.nearHouseImg0.position = cc.v2(this.nearHouseImg1.position.x + nw, this.nearHouseImg0.position.y);
            }
        })));
        this.nearHouseImg1.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-300, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
            if(this.nearHouseImg1.position.x <= -nw - this._winSize.width / 2){
                this.nearHouseImg1.position = cc.v2(this.nearHouseImg0.position.x + nw, this.nearHouseImg1.position.y);
            }
        })));

        //远处地面
        let ffw = this.farFloorImg0.width;
        this.farFloorImg0.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-400, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
            if(this.farFloorImg0.position.x <= -ffw - this._winSize.width / 2){
                this.farFloorImg0.position = cc.v2(this.farFloorImg1.position.x + ffw, this.farFloorImg0.position.y);
            }
        })));
        this.farFloorImg1.runAction(cc.sequence(cc.moveBy(2.0, cc.v2(-400, 0)), cc.delayTime(0.1), cc.callFunc(() =>{
            if(this.farFloorImg1.position.x <= -ffw - this._winSize.width / 2){
                this.farFloorImg1.position = cc.v2(this.farFloorImg0.position.x + ffw, this.farFloorImg1.position.y);
            }
        })));

        //近处地面
        let nfw = this.nearFloorImg0.width;
        for(let i = 0; i < 100; i++){
            this.nearFloorImg0.runAction(cc.sequence(cc.delayTime(0.02 * i), cc.callFunc(() =>{
                if(i % 9 == 0){
                    this.playSound("sound/walk", false);
                }
                let pX1 = this.nearFloorImg0.position.x - 4;
                this.nearFloorImg0.position =  cc.v2(pX1, this.nearFloorImg0.position.y);

                let pX2 = this.nearFloorImg1.position.x - 4;
                this.nearFloorImg1.position = cc.v2(pX2, this.nearFloorImg1.position.y);

                if(pX1 <= -nfw - this._winSize.width / 2){
                    this.nearFloorImg0.position = cc.v2(this.nearFloorImg1.position.x + nfw, this.nearFloorImg0.position.y);
                }
                if(pX2 <= -nfw - this._winSize.width / 2){
                    this.nearFloorImg1.position = cc.v2(this.nearFloorImg0.position.x + nfw, this.nearFloorImg1.position.y);
                }
            })));
        }
    },

    //敌方开炮
    enemyOpenFire : function(){
        //敌方子弹世界坐标
        let enemyBulletPos = this._enemyNode.enemyBulletWorldPos();
        //我方英雄世界坐标
        let myHeroPos = this.myHeroImg.parent.convertToWorldSpaceAR(cc.v2(this.myHeroImg.position.x, this.myHeroImg.position.y + 30));

        //计算夹角
        let lenX = Math.abs(enemyBulletPos.x - myHeroPos .x);
        let lenY = Math.abs(enemyBulletPos.y - myHeroPos .y);
        let angle = Math.atan2(lenY, lenX) * 180 / Math.PI;

        //设置敌方小火炮的角度
        this._enemyNode.setGunAngle(angle);

        //计算炮运行的距离
        let len = Math.sqrt(Math.pow(lenX, 2) + Math.pow(lenY, 2));
        this._enemyNode.gunAni(len);
        this.playSound("sound/enemyBullet", false);
    },

    //刷新英雄的血量
    setBloodValue : function(){
        //设置盾牌透明度
        let p = this._heroBloodValue / 100;
        this.shieldImg.opacity = Math.floor(p * 255);
        //设置血量进度
        this.bloodBar.progress = p;
    },

    //我方英雄死亡动画
    myHeroDie : function(){
        this.heroDieParticle.node.active = true;
        this.heroDieParticle.stopSystem();
        this.heroDieParticle.resetSystem();
        //隐藏我方英雄
        this.heroNode.active = false;
    },

    //游戏结束
    gameOver : function(){
        this.node.runAction(cc.sequence(cc.delayTime(1.0),cc.callFunc(() =>{
            //显示结算界面
            this.endLayer.active = true;
            //显示最高得分
            let bestScore = parseInt(cc.sys.localStorage.getItem("gunBestScore")) || 0;
            if(this._curScore > bestScore){
                this.bestScoreText.string = this._curScore;
                cc.sys.localStorage.setItem("gunBestScore", this._curScore);
            }
            else{
                this.bestScoreText.string = bestScore;
            }
            //显示当前得分
            this.allScoreText.string = this._curScore;
        })));
    },

    // 按钮的回调
    exitCallBack : function(event, customEventData){
        this.playSound("sound/click", false);
        cc.director.preloadScene('start', function () {
            cc.director.loadScene('start');
        });
    },

    //重新开始回调
    refreshCallBack : function(event, customEventData){
        this.playSound("sound/click", false);
        cc.director.preloadScene('playScene', function () {
            cc.director.loadScene('playScene');
        });
    },

    //屏幕触摸回调
    onEventStart : function(event){
        if(!this._canShooting){
            return;
        }
        cc.log("onEventStart");
        this.updateGunAngle();
    },

    onEventMove : function(event){
        cc.log("onEventMove");
    },

    onEventEnd : function(event){
        if(!this._canShooting){
            return;
        }
        cc.log("onEventEnd");
        this.playSound("sound/heroBullet", false);
        this._canShooting = false;
        this.stopGunAngle();
        this.setBulletBody(this.myBulletImg);

        let x = 5000; 
        //2号子弹体积较大,需要更大的力
        if(this.heroType == 1){
            x = 7000; 
        }
        //通过角度计算力度
        let y = x * Math.tan(Math.abs(this._curAngle) * (Math.PI / 180)); 
        //给子弹设置冲量
        this.bulletNode.getComponent(cc.RigidBody).applyForceToCenter(cc.v2(x, y));

        let curPos = this.bulletNode.position;
        let lastPos = curPos;
        this.bulletfun = function(){
            curPos = this.bulletNode.position;
            //计算角度
            let lenX = curPos.x - lastPos.x;
            let lenY = 0;
            let r = 0;
            if(curPos.y < lastPos.y){ //向上运动
                lenY = curPos.y - lastPos.y;
                r = Math.atan2(lenY, lenX) * 180 / Math.PI;
            }
            else{   //向下运动
                lenY = lastPos.y - curPos.y;
                r = -1 * Math.atan2(lenY, lenX) * 180 / Math.PI;
            }
            lastPos = curPos;
            this.bulletNode.angle = r;
        };
        this.schedule(this.bulletfun, 0.1);
    },

    onEventCancel : function(event){
        this.onEventEnd(event);
    },

    //刷新得分
    updateScore : function(){
        this._curScore += 1;
        this.scoreText.string = this._curScore;
        this.playSound("sound/addScore", false);
    },

    //更换纹理
    setImgTexture : function(str, node){
        cc.loader.loadRes(str, cc.SpriteFrame, function (err, spriteFrame) {
            if (err) {
                cc.error(err.message || err);
                return;
            }
            node.getComponent(cc.Sprite).spriteFrame = spriteFrame;
        }.bind(this));
    },

    //播放音效
    playSound : function(name, isLoop){
        cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
            if(err){
                return;
            }
            var audioID = cc.audioEngine.playEffect(clip, isLoop);
        });
    },

    update: function (dt) {

    },
});






//-------------gameStart.js------------------

cc.Class({
    extends: cc.Component,

    properties: {
        heroBtn : {
            default: [],
            type: cc.Button,
        },
    },

    onLoad: function () {
        //设置当前选择的英雄
        let tag = parseInt(cc.sys.localStorage.getItem("gunHeroType") || 0);
        for(let i = 0; i < 4; i++){
            let hero = this.heroBtn[i];
            hero.interactable = true;
        }
        let hero = this.heroBtn[tag];
        hero.interactable = false;
    },

    //开始按钮回调
    startBtnCallBack : function(event, customEventData){
        this.playSound("sound/click", false);
        //显示游戏界面
        cc.log("startBtnCallBack"); 
        cc.director.preloadScene('playScene', function () {
            cc.director.loadScene('playScene');
        });
    },

    //选择英雄按钮的回调
    selectHeroCallBack : function(event, customEventData){
        this.playSound("sound/select", false);
        let tag = parseInt(customEventData);
        for(let i = 0; i < 4; i++){
            let hero = this.heroBtn[i];
            hero.interactable = true;
        }
        let hero = this.heroBtn[tag];
        hero.interactable = false;

        //保存当前选择的英雄
        cc.sys.localStorage.setItem("gunHeroType", tag);
    },

    //播放音效
    playSound : function(name, isLoop){
        cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {
            if(err){
                return;
            }
            let audioID = cc.audioEngine.playEffect(clip, isLoop);
        });
    },

    // called every frame
    update: function (dt) {

    },
});









//-------------spriteFrameAni.js------------------

cc.Class({
    extends: cc.Component,
    properties: {
        bigImg : cc.SpriteAtlas,
    },

    onLoad () {
        
    },

    playAni(nameStr, count, dt, isLoop){
        this.stopAni();
        this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + 0);
        let array = [];
        for(let i = 0; i < count; i++){
            array.push(cc.delayTime(dt));
            array.push(cc.callFunc(() =>{
                this.node.getComponent(cc.Sprite).spriteFrame = this.bigImg.getSpriteFrame(nameStr + i);
            }));
        }
        
        if(isLoop){
            this.node.runAction(cc.repeatForever(cc.sequence(array)));
        }
        else{
            this.node.runAction(cc.sequence(array));
        }
    },

    stopAni(){
        this.node.stopAllActions();
    },

    onDestroy () {

    },
});









感谢:

本文转载自 https://mp.weixin.qq.com/s/K932G6FvIE-5foQGgKraug 这篇文章,这里感谢原作者对于技术的分享。

下载:

本文章源码和资源下载地址

发布了265 篇原创文章 · 获赞 20 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/ccnu027cs/article/details/103520487