《飛機大戰(一)》介紹攝像機實現地圖的滾動和子彈組件的設計;在此基礎上《飛機大戰(二)》增加了子彈的角度直線發射以及動態角度更新能力,用於實現如:散彈、螺旋掃射等華麗的子彈表現。
本次教程分享的是 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 提供的碰撞系統:碰撞組件、碰撞分組、碰撞事件監聽,可以很方便地實現遊戲中的碰撞處理。
當碰撞產生時,所有關聯的碰撞對象都會收到碰撞回調通知,因此可以減少對其它模塊的依賴,儘可能各自處理自身的遊戲邏輯,比如:子彈碰撞只管自己的銷燬,它碰到誰都一樣(根據具體邏輯處理),如果敵機有盔甲防禦等複雜的機制,要以由敵機模塊處理傷害計算。
最後需要注意凹多邊形問題,儘可能使用矩形、圓型碰撞,如果必須使用多邊形碰撞,碰撞接觸面不要有凹陷。
歡迎關注我的公衆號,我們一起成長!