• 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);

    获取代码

    关注公众号,发送【大炮英雄】,获取代码。

  • 相关阅读:
    C#与SAP进行数据交互
    自动加减工单结存算法实现
    RDLC报表打印一维码
    调用存储过程通用类
    监听网络状态
    压缩及解压缩文件
    用Go造轮子-管理集群中的配置文件
    2015年总结
    浅析Go语言的Interface机制
    2014年总结
  • 原文地址:https://www.cnblogs.com/caizj/p/11691485.html
Copyright © 2020-2023  润新知