游戏开发中,碰撞检测无处不在,今天就通过一个简单的小游戏教你学会如何在 Cocos Creator 中进行碰撞检测。配合官方文档学习效果更加(官方文档传送门:https://docs.cocos.com/creator/manual/zh/physics/collision/)
游戏玩法:
通过控制手枪位置,松手发射子弹击中躲在人质后面的歹徒顺利解救人质,小心不要打中人质哦!
实现逻辑:
分别给子弹、人质和歹徒添加碰撞组件,检测到子弹与歹徒发生碰撞时,营救成功;检测到子弹与人质发生碰撞时,营救失败。
步骤详解:
1.按照图中节点树创建节点,分别将对应贴图拖给对应的节点,并设置节点位置如图,successLabel 和 failLabel 内容分别为「解救成功!」和「解救失败!」:
2.给 hostage 节点添加碰撞组件,并设置组件 Tag 属性和 Size 属性:
当一个节点上有多个碰撞组件时,在发生碰撞后,可以使用 Tag 来判断是节点上的哪个碰撞组件被碰撞了。此时,碰撞组件大小和节点大小一致,同样的步骤将 enemy 和 bullet 节点添加好碰撞组件。
3.接下来在项目设置面板里添加分组:hostage、enemy 和 bullet(注:分组添加后是不可以删除的,不过你可以任意修改分组的名字),并勾选hostage 和 bullet、enemy 和 bullet:
4.在项目设置添加好分组后,分别在 hostage、enemy 和 bullet 属性中的 Group 设置对应分组:
5.接下来新建 Bullet.js 脚本挂载到 bullet 节点下,编辑脚本如下,主要在 update 方法内实现了子弹的移动和销毁,以及碰撞回调函数(注:使用碰撞检测之前一定要获取碰撞检测,且碰撞回调函数名称固定,无需注册!):
// Bullet.js
cc.Class({
extends: cc.Component,
properties: {
mSpeed: 300,
},
// LIFE-CYCLE CALLBACKS:
// onLoad () {},
start() {
var manager = cc.director.getCollisionManager(); // 获取碰撞检测系统
manager.enabled = true;
},
update(dt) { // 设置子弹移动,当超出屏幕范围未发生碰撞时自动销毁
this.node.y += this.mSpeed * dt;
if (this.node.y > 580) {
console.log('超出屏幕范围,子弹销毁!');
this.node.destroy();
}
},
/**
* 当碰撞产生的时候调用
* @param {Collider} other 产生碰撞的另一个碰撞组件
* @param {Collider} self 产生碰撞的自身的碰撞组件
*/
onCollisionEnter: function (other, self) {
console.log('on collision enter');
if (other.tag == 1) { // 子弹碰到人质时,解救失败!
console.log('解救人质失败!');
var failLabel = this.node.parent.getChildByName('failLabel');
failLabel.active = true;
this.node.destroy();
} else if (other.tag == 2) { // 子弹碰到敌人时,解救成功!
console.log('解救人质成功!');
var successLabel = this.node.parent.getChildByName('successLabel');
successLabel.active = true;
this.node.destroy();
}
},
/**
* 当碰撞产生后,碰撞结束前的情况下,每次计算碰撞结果后调用
* @param {Collider} other 产生碰撞的另一个碰撞组件
* @param {Collider} self 产生碰撞的自身的碰撞组件
*/
onCollisionStay: function (other, self) {
console.log('on collision stay');
},
/**
* 当碰撞结束后调用
* @param {Collider} other 产生碰撞的另一个碰撞组件
* @param {Collider} self 产生碰撞的自身的碰撞组件
*/
onCollisionExit: function (other, self) {
console.log('on collision exit');
}
});
编写完脚本后,将 bullet 节点保存为预制件待用。
6.然后编写 gun 节点的控制逻辑脚本 ControlGun.js:
// ControlGun.js
cc.Class({
extends: cc.Component,
properties: {
mBullet: cc.Prefab
},
// LIFE-CYCLE CALLBACKS:
onLoad() { },
start() {
this.node.on('touchstart', this.onTouchStart, this);
this.node.on('touchmove', this.onTouchMove, this);
this.node.on('touchend', this.ontouchEnd, this);
},
// update (dt) {},
onTouchStart(event) { // 每次点击之前,都要把结果关掉
var successLabel = this.node.parent.getChildByName('successLabel');
successLabel.active = false;
var failLabel = this.node.parent.getChildByName('failLabel');
failLabel.active = false;
},
onTouchMove(event) { // 控制节点在屏幕范围内左右移动
let rangePos = event.getDelta();
this.node.x += rangePos.x;
let minX = -this.node.parent.width / 2 + this.node.width / 2;
let maxX = Math.abs(minX);
let currentPos = this.node.getPosition();
if (currentPos.x < minX) {
currentPos.x = minX;
} else if (currentPos.x > maxX) {
currentPos.x = maxX;
}
this.node.setPosition(currentPos);
},
ontouchEnd(event) { // 松开时发射子弹
console.log('发射子弹');
let bullet = cc.instantiate(this.mBullet);
bullet.parent = this.node.parent;
let currentPos = this.node.getPosition();
bullet.parent = this.node.parent;
bullet.setPosition(currentPos);
}
});
7.最后编写 enemy 的移动脚本:
// ControlEnemy.js
cc.Class({
extends: cc.Component,
properties: {
mSpeed: 300
},
// LIFE-CYCLE CALLBACKS:
// onLoad () {},
start() {
this.minX = -this.node.parent.width / 2 + this.node.width / 2;
this.maxX = Math.abs(this.minX);
},
update(dt) {
let currentPos = this.node.getPosition();
if (currentPos.x < this.minX) {
this.mSpeed = Math.abs(this.mSpeed);
} else if (currentPos.x > this.maxX) {
this.mSpeed = -Math.abs(this.mSpeed);
}
this.node.x += this.mSpeed * dt;
}
});
8.编写完所有的脚本之后,就可以预览游戏了,快来试试你能不能成功的就下人质吧!
//----------------Bullet.js----------------------------
// Bullet.jscc.Class({extends: cc.Component,properties: {mSpeed: 300,},// LIFE-CYCLE CALLBACKS:// onLoad () {},start() {var manager = cc.director.getCollisionManager(); // 获取碰撞检测系统manager.enabled = true;},update(dt) { // 设置子弹移动,当超出屏幕范围未发生碰撞时自动销毁this.node.y += this.mSpeed * dt;if (this.node.y > 580) {console.log('超出屏幕范围,子弹销毁!');this.node.destroy();}},/*** 当碰撞产生的时候调用* @param {Collider} other 产生碰撞的另一个碰撞组件* @param {Collider} self 产生碰撞的自身的碰撞组件*/onCollisionEnter: function (other, self) {console.log('on collision enter');if (other.tag == 1) { // 子弹碰到人质时,解救失败!console.log('解救人质失败!');var failLabel = this.node.parent.getChildByName('failLabel');failLabel.active = true;this.node.destroy();} else if (other.tag == 2) { // 子弹碰到敌人时,解救成功!console.log('解救人质成功!');var successLabel = this.node.parent.getChildByName('successLabel');successLabel.active = true;this.node.destroy();}},/*** 当碰撞产生后,碰撞结束前的情况下,每次计算碰撞结果后调用* @param {Collider} other 产生碰撞的另一个碰撞组件* @param {Collider} self 产生碰撞的自身的碰撞组件*/onCollisionStay: function (other, self) {console.log('on collision stay');},/*** 当碰撞结束后调用* @param {Collider} other 产生碰撞的另一个碰撞组件* @param {Collider} self 产生碰撞的自身的碰撞组件*/onCollisionExit: function (other, self) {console.log('on collision exit');}
});//----------------ControlEnemy.js----------------------------
// ControlEnemy.jscc.Class({extends: cc.Component,properties: {mSpeed: 300},// LIFE-CYCLE CALLBACKS:// onLoad () {},start() {this.minX = -this.node.parent.width / 2 + this.node.width / 2;this.maxX = Math.abs(this.minX);},update(dt) {let currentPos = this.node.getPosition();if (currentPos.x < this.minX) {this.mSpeed = Math.abs(this.mSpeed);} else if (currentPos.x > this.maxX) {this.mSpeed = -Math.abs(this.mSpeed);}this.node.x += this.mSpeed * dt;}
});//----------------ControlGun.js----------------------------// ControlGun.jscc.Class({extends: cc.Component,properties: {mBullet: cc.Prefab},// LIFE-CYCLE CALLBACKS:onLoad() { },start() {this.node.on('touchstart', this.onTouchStart, this);this.node.on('touchmove', this.onTouchMove, this);this.node.on('touchend', this.ontouchEnd, this);},// update (dt) {},onTouchStart(event) { // 每次点击之前,都要把结果关掉var successLabel = this.node.parent.getChildByName('successLabel');successLabel.active = false;var failLabel = this.node.parent.getChildByName('failLabel');failLabel.active = false;},onTouchMove(event) { // 控制节点在屏幕范围内左右移动let rangePos = event.getDelta();this.node.x += rangePos.x;let minX = -this.node.parent.width / 2 + this.node.width / 2;let maxX = Math.abs(minX);let currentPos = this.node.getPosition();if (currentPos.x < minX) {currentPos.x = minX;} else if (currentPos.x > maxX) {currentPos.x = maxX;}this.node.setPosition(currentPos);},ontouchEnd(event) { // 松开时发射子弹console.log('发射子弹');let bullet = cc.instantiate(this.mBullet);bullet.parent = this.node.parent;let currentPos = this.node.getPosition();bullet.parent = this.node.parent;bullet.setPosition(currentPos);}
});
感谢:
本文转载自https://mp.weixin.qq.com/s/7VJG2OMwXK4r2lQ-Qw9HNA这篇文章,这里感谢原作者对于技术的分享。
下载:
本文章源码和资源下载地址