查看原文
其他

CreatorPrimer|飞机大战(一)

张晓衡 Creator星球游戏开发社区 2021-08-09

前两天在Cocos官方公众号上学习了「大掌教」的Cocos Creator 2.x Camera教程,总算是对摄像机组件有了一个初步的认识,乘热打铁Shawn用Camera摄像机练习了一个飞机大战游戏,目前主要实现3个功能:

1.无限滚动背景  2.控制飞机移动   3.子弹发射

本次教程是图文+视频的超强组合

如果你对编写代码不感兴趣或怕看不明白,建议先现看下面视频

1. 无限滚动背景

滚动背景我们是使用最新的摄像机来实现,我这里做了一个卷轴摄像机组件ScrollCamera,我们先来看一下组件暴露的属性

ScrollCamera组件很像真实世界中的摄像机的推进器,Speed是推进速度,LoopGrounds是一个节点数组,他们是一组可首尾衔接的精灵节点

我们再看一下ScrollCamera组件的代码

  1. cc.Class({

  2. editor: {

  3. requireComponent: cc.Camera, //前置要求摄像机组件

  4. },

  5. extends: cc.Component,


  6. properties: {

  7. speed: 300, //滚动速度

  8. loopGrounds: [cc.Node], //循环节点

  9. },


  10. start () {

  11. //获取节点上的摄像机组件

  12. this.camera = this.getComponent(cc.Camera);

  13. },


  14. /**

  15. *每帧更新函数

  16. *1. 更新摄像机位置

  17. *2. 检查循环节点,设置新位置

  18. **/

  19. update(dt) {

  20. //获取当前节点

  21. let current = this.loopGrounds[0];

  22. //计算当前节点在摄像机中的位置

  23. let pt = this.camera.getWorldToCameraPoint(current.position);

  24. //当前节点超出摄像机范围(摄像机可视范围就是屏幕大小)

  25. if (pt.y <= -cc.winSize.height) {

  26. //取最后一个地图节点

  27. let last = this.loopGrounds[this.loopGrounds.length - 1];

  28. //将当前节点从数组中移除

  29. this.loopGrounds.shift();

  30. //将当前节点放到数组最后

  31. this.loopGrounds.push(current);

  32. //将当前节点位置移动到最顶部位置

  33. current.y = last.y + (last.height + current.height) / 2;

  34. }

  35. //更新摄像机节点位置

  36. this.node.y += dt * this.speed;

  37. }

  38. });

推动摄像机的代码很简单,update函数中的最后一行

  1. this.node.y += dt * this.speed;

update中前面的几行代码是在做loopGrounds节点的检查和位置更新,每一行都注释的哦!这里就不再过多赘述。

直接将这个组件拖动到场景编辑器或层级管理器即可,设置background节点为background分组

同时设置ScrollCamera的cullingMask属性只勾选background,看下图

通过上面的设置和ScrollCamera的十几代码,无限滚动背景就搞定了。

2. 控制飞机移动

不知道大家还记得公众号之前的一篇文章《Cocos Creator基础教程(11)—可拖拽组件》

我直接将Dragable.js组件脚本拿过来,挂载到飞机节点上就OK了,代码很简单

  1. /**

  2. * 可拖动组件

  3. */

  4. cc.Class({

  5. extends: cc.Component,


  6. onLoad() {

  7. //注册TOUCH_MOVE事件

  8. this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);

  9. cc.log('onload');

  10. },


  11. _onTouchMove(touchEvent) {

  12. //let location = touchEvent.getLocation();

  13. //this.node.position = this.node.parent.convertToNodeSpaceAR(location);


  14. //获取触摸移动增量

  15. let delta = touchEvent.getDelta();

  16. //当前节点位置+增量,更新节点位置

  17. this.node.position = delta.add(this.node.position);

  18. }

  19. });

Shawn在做这个飞机游戏过程中,尝试了消灭病毒当下这个火热的游戏,他的整个屏幕任意位置都可以控制飞机移动,它是怎么做的呢?大家先可以想一下自己的方案...

我这里的方案是修改一下Dragable组件,增加一个target节点属性,将它从飞机节点上移到外层foreground节点,看下图

触摸事件发生在foreground节点上,但移动的是target属性所指向的节点,看下面代码

  1. /**

  2. * 可拖动组件

  3. */

  4. cc.Class({

  5. extends: cc.Component,

  6. properties: {

  7. target: cc.Node,

  8. },

  9. ...

  10. _onTouchMove(touchEvent) {

  11. //获取触摸移动增量

  12. let delta = touchEvent.getDelta();

  13. //如果this.target未设置,使用移动当前节点(兼容之前的用法)

  14. let node = this.target || this.node;

  15. //当前节点位置+增量,更新节点位置

  16. node.position = delta.add(node.position);

  17. }

  18. });

代码就增加了一个target节点的定义,在TouchMove事件中检查this.target存在就用它,不存在默认移动当前节点,这样可以兼容曾经该组件的地方,不用做修改。

3. 子弹发射

飞机游戏的一个亮点就是子弹发射的华丽视觉效果,Shawn在网上找了些子弹特效图片。

我们编辑一个子弹Bullet的预制体,这里使用到之前文章《Cocos Creator基础教程(12)—精灵变身》中的SpriteEx.js组件

SpriteEx上面配置了几张子弹图片,使用index属性可以方便切换子弹的表现效果

Bullet子弹只是表现效果,要让子弹运动起来,我这里编写了一个LineEmmiter.js(线性发射器)的脚本

将它挂载到飞机节点上,用它来实例化Bullet预制体并让它动起来,先看一下LineEmmiter组件的属性:

之前的文章中提到过:组件为节点赋予能力

飞机节点上有一个Sprite可显示图片纹理

我们再挂上LineEmmiter组件,让它具有发射子弹的能力。

发射器的主要属性是子弹预制体、发射频率、子弹飞行速度

OffsetX属性要特别一点,它可以控制子弹与飞机的偏移位置,以实现同时发射多行子弹的效果,看下图

我们再看发射器组件代码

  1. cc.Class({

  2. extends: cc.Component,


  3. properties: {

  4. prefab: cc.Prefab,

  5. rate: 1, //发射间隔

  6. speed: 1000, //移动速度

  7. offsetX: 0,

  8. },


  9. start() {

  10. this.schedule(this._emmitNode, this.rate);

  11. },


  12. _emmitNode() {

  13. //实例化节点,设置位置&父节

  14. let node = cc.instantiate(this.prefab);

  15. node.position = this.node.position;

  16. node.x += this.offsetX;

  17. node.parent = this.node.parent;

  18. //计算子弹需要飞行的距离,飞行时间 = 距离 / 速度

  19. let distance = ((cc.winSize.height / 2) - this.node.y);

  20. let duration = distance / this.speed;

  21. //使用moveBy动作,完成后删除子弹节点

  22. let moveBy = cc.moveBy(duration, cc.v2(0, distance));

  23. let removeSelf = cc.removeSelf();

  24. let sequence = cc.sequence(moveBy, removeSelf);

  25. node.runAction(sequence);

  26. }

  27. });


发射器代码也很简单

1.创建子弹

2.让子弹飞

我们这里子弹是垂直飞行的,直接使moveBy动作就可以完成

子弹从当前飞机节点出发直到屏幕顶部结束

公式:距离/速度=时间

计算每颗子弹的飞行时间,保证飞机在不同位置,所有子弹都是按同样的速度飞行。

4. 小结

本次教程我们实现了一个最小飞机游戏的简单原型

核心地图滚动与子弹发射代码只有70多行,有没有觉得使用Cocos Creator开发游戏飞一般的简单呢...


不过还有很多欠缺的地方

比如:限制飞机不要跑出屏幕之外、子弹应该使用内存池进行优化

在功能上还缺少敌机生成、少子弹碰撞、得分计算等等,这些内容我们留到下次继续。

对本次教程源码感兴趣的同学可以在公众号回复:“飞机”或“飞机大战


如果你对飞机游戏有不同的实现方案,欢迎留言讨论!




欢迎关注「奎特尔星球」公众号,欢迎大家投稿,来我们一起成长!

「奎特尔星球」微信公众号

「奎特尔星球」博客网站,建设中...

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存