CreatorPrimer|飞机大战(一)
前两天在Cocos官方公众号上学习了「大掌教」的Cocos Creator 2.x Camera教程,总算是对摄像机组件有了一个初步的认识,乘热打铁Shawn用Camera摄像机练习了一个飞机大战游戏,目前主要实现3个功能:
1.无限滚动背景 2.控制飞机移动 3.子弹发射
本次教程是图文+视频的超强组合
如果你对编写代码不感兴趣或怕看不明白,建议先现看下面视频
1. 无限滚动背景
滚动背景我们是使用最新的摄像机来实现,我这里做了一个卷轴摄像机组件ScrollCamera,我们先来看一下组件暴露的属性
ScrollCamera组件很像真实世界中的摄像机的推进器,Speed是推进速度,LoopGrounds是一个节点数组,他们是一组可首尾衔接的精灵节点
我们再看一下ScrollCamera组件的代码
cc.Class({
editor: {
requireComponent: cc.Camera, //前置要求摄像机组件
},
extends: cc.Component,
properties: {
speed: 300, //滚动速度
loopGrounds: [cc.Node], //循环节点
},
start () {
//获取节点上的摄像机组件
this.camera = this.getComponent(cc.Camera);
},
/**
*每帧更新函数
*1. 更新摄像机位置
*2. 检查循环节点,设置新位置
**/
update(dt) {
//获取当前节点
let current = this.loopGrounds[0];
//计算当前节点在摄像机中的位置
let pt = this.camera.getWorldToCameraPoint(current.position);
//当前节点超出摄像机范围(摄像机可视范围就是屏幕大小)
if (pt.y <= -cc.winSize.height) {
//取最后一个地图节点
let last = this.loopGrounds[this.loopGrounds.length - 1];
//将当前节点从数组中移除
this.loopGrounds.shift();
//将当前节点放到数组最后
this.loopGrounds.push(current);
//将当前节点位置移动到最顶部位置
current.y = last.y + (last.height + current.height) / 2;
}
//更新摄像机节点位置
this.node.y += dt * this.speed;
}
});
推动摄像机的代码很简单,update函数中的最后一行
this.node.y += dt * this.speed;
update中前面的几行代码是在做loopGrounds节点的检查和位置更新,每一行都注释的哦!这里就不再过多赘述。
直接将这个组件拖动到场景编辑器或层级管理器即可,设置background节点为background分组
同时设置ScrollCamera的cullingMask属性只勾选background,看下图
通过上面的设置和ScrollCamera的十几代码,无限滚动背景就搞定了。
2. 控制飞机移动
不知道大家还记得公众号之前的一篇文章《Cocos Creator基础教程(11)—可拖拽组件》
我直接将Dragable.js组件脚本拿过来,挂载到飞机节点上就OK了,代码很简单
/**
* 可拖动组件
*/
cc.Class({
extends: cc.Component,
onLoad() {
//注册TOUCH_MOVE事件
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
cc.log('onload');
},
_onTouchMove(touchEvent) {
//let location = touchEvent.getLocation();
//this.node.position = this.node.parent.convertToNodeSpaceAR(location);
//获取触摸移动增量
let delta = touchEvent.getDelta();
//当前节点位置+增量,更新节点位置
this.node.position = delta.add(this.node.position);
}
});
Shawn在做这个飞机游戏过程中,尝试了消灭病毒当下这个火热的游戏,他的整个屏幕任意位置都可以控制飞机移动,它是怎么做的呢?大家先可以想一下自己的方案...
我这里的方案是修改一下Dragable组件,增加一个target节点属性,将它从飞机节点上移到外层foreground节点,看下图
触摸事件发生在foreground节点上,但移动的是target属性所指向的节点,看下面代码
/**
* 可拖动组件
*/
cc.Class({
extends: cc.Component,
properties: {
target: cc.Node,
},
...
_onTouchMove(touchEvent) {
//获取触摸移动增量
let delta = touchEvent.getDelta();
//如果this.target未设置,使用移动当前节点(兼容之前的用法)
let node = this.target || this.node;
//当前节点位置+增量,更新节点位置
node.position = delta.add(node.position);
}
});
代码就增加了一个target节点的定义,在TouchMove事件中检查this.target存在就用它,不存在默认移动当前节点,这样可以兼容曾经该组件的地方,不用做修改。
3. 子弹发射
飞机游戏的一个亮点就是子弹发射的华丽视觉效果,Shawn在网上找了些子弹特效图片。
我们编辑一个子弹Bullet的预制体,这里使用到之前文章《Cocos Creator基础教程(12)—精灵变身》中的SpriteEx.js组件
在SpriteEx上面配置了几张子弹图片,使用index属性可以方便切换子弹的表现效果
Bullet子弹只是表现效果,要让子弹运动起来,我这里编写了一个LineEmmiter.js(线性发射器)的脚本
将它挂载到飞机节点上,用它来实例化Bullet预制体并让它动起来,先看一下LineEmmiter组件的属性:
之前的文章中提到过:组件为节点赋予能力
飞机节点上有一个Sprite可显示图片纹理
我们再挂上LineEmmiter组件,让它具有发射子弹的能力。
发射器的主要属性是子弹预制体、发射频率、子弹飞行速度
OffsetX属性要特别一点,它可以控制子弹与飞机的偏移位置,以实现同时发射多行子弹的效果,看下图
我们再看发射器组件代码
cc.Class({
extends: cc.Component,
properties: {
prefab: cc.Prefab,
rate: 1, //发射间隔
speed: 1000, //移动速度
offsetX: 0,
},
start() {
this.schedule(this._emmitNode, this.rate);
},
_emmitNode() {
//实例化节点,设置位置&父节
let node = cc.instantiate(this.prefab);
node.position = this.node.position;
node.x += this.offsetX;
node.parent = this.node.parent;
//计算子弹需要飞行的距离,飞行时间 = 距离 / 速度
let distance = ((cc.winSize.height / 2) - this.node.y);
let duration = distance / this.speed;
//使用moveBy动作,完成后删除子弹节点
let moveBy = cc.moveBy(duration, cc.v2(0, distance));
let removeSelf = cc.removeSelf();
let sequence = cc.sequence(moveBy, removeSelf);
node.runAction(sequence);
}
});
发射器代码也很简单
1.创建子弹
2.让子弹飞
我们这里子弹是垂直飞行的,直接使moveBy动作就可以完成
子弹从当前飞机节点出发直到屏幕顶部结束
公式:距离/速度=时间
计算每颗子弹的飞行时间,保证飞机在不同位置,所有子弹都是按同样的速度飞行。
4. 小结
本次教程我们实现了一个最小飞机游戏的简单原型
核心地图滚动与子弹发射代码只有70多行,有没有觉得使用Cocos Creator开发游戏飞一般的简单呢...
不过还有很多欠缺的地方
比如:限制飞机不要跑出屏幕之外、子弹应该使用内存池进行优化
在功能上还缺少敌机生成、少子弹碰撞、得分计算等等,这些内容我们留到下次继续。
对本次教程源码感兴趣的同学可以在公众号回复:“飞机”或“飞机大战”
如果你对飞机游戏有不同的实现方案,欢迎留言讨论!
欢迎关注「奎特尔星球」公众号,欢迎大家投稿,来我们一起成长!
「奎特尔星球」微信公众号
「奎特尔星球」博客网站,建设中...