CreatorPrimer|飞机大战(三)
《飞机大战(一)》介绍摄像机实现地图的滚动和子弹组件的设计;在此基础上《飞机大战(二)》增加了子弹的角度直线发射以及动态角度更新能力,用于实现如:散弹、螺旋扫射等华丽的子弹表现。
本次教程分享的是 Cocos Creator 引擎碰撞检测系统,使玩家的子弹能够击中敌人,让我们的游戏可以真正玩起来!
子弹预制件
子弹发射器 LineEmitter,用于控制子弹的飞行路径,子弹自身的表现则由预制体 Bullet 呈现,看下图:
Bullet 预制体设计了两层,其中 image 节点是子弹的纹理图片,为什么没有直接在 Bullet 节点上挂 Sprite 呢?
这里考虑的是子弹有可能是静态图片,还有可能是动画序列帧(比如带雷电属性的子弹、火焰喷射器),为了增强灵活性,因此将子弹的表现放在了 Bullet 节点的内部。
子弹组件
在 Bullet 子弹预制体上挂载一个同名的 Bullet 组件脚本,
设置子的伤害属性,
监听碰撞事件做相应的处理
看下面代码:
let Bullet = cc.Class({
extends: cc.Component,
properties: {
damage: 1,
},
onLoad() {
//穿透力
this.penetrate = 0;
},
onCollisionEnter(other, self) {
//如果子弹有穿透效果,可以在此控制
this.penetrate--;
if (this.penetrate <= 0) {
//销毁节点
this.node.destroy();
}
},
});
module.exports = Bullet;
子弹组件脚本主要是控制子弹在碰撞产生时的表现:销毁节点。
在游戏的制作过程中,Shawn 又为子弹添加了穿透的能力,因此增加了一个 penetrate 的内部属性,用于控制子弹可穿透几次。
敌机预制件
敌机预制体编辑与子弹相仿,看下图:
下面说明一下敌机预制体的设计思路:
在 Enemy 内部放入一个 image 节点,用于显示飞机的外型,有可能飞机的呈现不仅仅是一张静态图片,很有可能是一组动画,为了灵活扩展,所以没有将Sprite直接挂载到Enemy上。
同时飞机还带有一个血条,使用同名的 Enemy 组件监听碰撞、控制内部的血条组件显示。
Enemy节点上挂载碰撞组件,你需要根据 image 节点的外型选择是使用矩形碰撞组件还是圆形碰撞组件,不建议使用多边形碰撞组件。 【视频】
飞机在飞行过程中并非是简单的垂直从上往下,而是会根据事先编辑的路径做曲线运动,UpdateRotation组件就是用于更新飞机自身的角度,让它的头部始终朝向前进的路线。
需要注意,不建议使用多边形碰撞组件,是因为Shawn在实践中发现凹多边型碰撞检测不精确,碰撞回调不能正确响应,看下面视频:
视频中以激光弹演示,子弹攻击到凹陷处不产生伤害,凸出处可以看到敌机持续消耗HP
具体原因还未深入研究,如果您对此有所了解或更好的方案,欢迎留言讨论。
敌机组件
下面是 Enemy 组件碰撞处理的主要代码:
cc.Class({
extends: cc.Component,
properties: {
maxHP: {...}, //使用属性控制血条UI
_hp: 0,
hp: {...}, //使用属性控制血条UI
},
start() {
this._collider = this.node.getComponent(cc.Collider);
},
_updateHpBar() {...},
//监听碰撞
onCollisionEnter(other, self) {
//检测碰撞对象是否为子弹
let bullet = other.getComponent('Bullet');
if (bullet) {
//使用子弹伤害减去当前hp
this.hp -= bullet.damage;
//hp小于等于0销毁节点
if (this.hp <= 0) {
this._playDestroy();
}
}
},
//播放飞机销毁动画
_playDestroy() {
//因为没有爆炸的特效资源,暂时使用淡出+缩放
this._collider.enabled = false;
let fadeOut = cc.fadeOut(0.5);
let scaleTo = cc.scaleTo(0.3, 0.1);
let spawn = cc.spawn(fadeOut, scaleTo);
let remove = cc.removeSelf();
this.node.runAction(cc.sequence(spawn, remove));
},
});
敌机处理碰撞需要识别碰撞对象,有可能是与玩家的子弹相碰,也有可能是与玩家的飞机相撞,通过 onCollisionEnter 碰撞回调的 other 参数可以知道是谁碰到了我(当前对象)。
碰撞分组
除了子弹、敌机预制体、组件的准备,还需要在引擎中编辑碰撞分组,这里先分析下游戏中有那些对象可能会参与碰撞,我这里列出了四个:
玩家飞机
玩家子弹
敌人飞机
敌机子弹
这里重点只介绍子弹的碰撞:
玩家的飞机发出子弹可以击中敌人的飞机,因此玩家子弹与敌人飞机是一对。
敌人飞机发出的子弹可以击中玩家飞机,因此敌人子弹与玩家飞机是一对。
为了使教程代码清晰简单,Shawn只设置了玩家子弹与敌人飞机的碰撞,至于玩家飞机与敌人飞机、敌机子弹与玩家飞机的碰撞就留给大家自行完成了(感觉是在绕口令...汗!)。
碰撞分组有了,设置子弹和敌机节点的Group属性:
小结
使用 Cocos Creator 提供的碰撞系统:碰撞组件、碰撞分组、碰撞事件监听,可以很方便地实现游戏中的碰撞处理。
当碰撞产生时,所有关联的碰撞对象都会收到碰撞回调通知,因此可以减少对其它模块的依赖,尽可能各自处理自身的游戏逻辑,比如:子弹碰撞只管自己的销毁,它碰到谁都一样(根据具体逻辑处理),如果敌机有盔甲防御等复杂的机制,要以由敌机模块处理伤害计算。
最后需要注意凹多边形问题,尽可能使用矩形、圆型碰撞,如果必须使用多边形碰撞,碰撞接触面不要有凹陷。
进入公众号回复:“碰撞检测”获取源码,感谢你的阅读,如果觉得教程对你有帮助,请转发给更多的朋友,愿我们一起成长!