CreatorPrimer | 飛機大戰(三)

《飛機大戰(一)》介紹攝像機實現地圖的滾動和子彈組件的設計;在此基礎上《飛機大戰(二)》增加了子彈的角度直線發射以及動態角度更新能力,用於實現如:散彈、螺旋掃射等華麗的子彈表現。

本次教程分享的是 Cocos Creator 引擎碰撞檢測系統,使玩家的子彈能夠擊中敵人,讓我們的遊戲可以真正玩起來!

子彈預製件

子彈發射器 LineEmitter,用於控制子彈的飛行路徑,子彈自身的表現則由預製體 Bullet 呈現,看下圖:

Bullet 預製體設計了兩層,其中 image 節點是子彈的紋理圖片,爲什麼沒有直接在 Bullet 節點上掛 Sprite 呢?

這裏考慮的是子彈有可能是靜態圖片,還有可能是動畫序列幀(比如帶雷電屬性的子彈、火焰噴射器),爲了增強靈活性,因此將子彈的表現放在了 Bullet 節點的內部。

子彈組件

在 Bullet 子彈預製體上掛載一個同名的 Bullet 組件腳本,

  1. 設置子彈的傷害屬性,
  2. 監聽碰撞事件做相應的處理

看下面代碼:

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 的內部屬性,用於控制子彈可穿透幾次。

敵機預製件

敵機預製體編輯與子彈相仿,看下圖:

敵機

下面說明一下敵機預製體的設計思路:

  1. 在 Enemy 內部放入一個 image 節點,用於顯示飛機的外型,有可能飛機的呈現不僅僅是一張靜態圖片,很有可能是一組動畫,爲了靈活擴展,所以沒有將Sprite直接掛載到Enemy上。
  2. 同時飛機還帶有一個血條,使用同名的 Enemy 組件監聽碰撞、控制內部的血條組件顯示。
  3. Enemy節點上掛載碰撞組件,你需要根據 image 節點的外型選擇是使用矩形碰撞組件還是圓形碰撞組件,不建議使用多邊形碰撞組件。
    【視頻】
  4. 飛機在飛行過程中並非是簡單的垂直從上往下,而是會根據事先編輯的路徑做曲線運動,UpdateRotation組件就是用於更新飛機自身的角度,讓它的頭部始終朝向前進的路線。

需要注意,不建議使用多邊形碰撞組件,是因爲Shawn在實踐中發現凹多邊型碰撞檢測不精確,碰撞回調不能正確響應,看下圖:
image.png

視頻中以激光彈演示,子彈攻擊到凹陷處不產生傷害,凸出處可以看到敵機持續消耗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 參數可以知道是誰碰到了我(當前對象)。

碰撞分組

除了子彈、敵機預製體、組件的準備,還需要在引擎中編輯碰撞分組,這裏先分析下游戲中有那些對象可能會參與碰撞,我這裏列出了四個:

  • 玩家飛機
  • 玩家子彈
  • 敵人飛機
  • 敵機子彈

這裏重點只介紹子彈的碰撞:

  1. 玩家的飛機發出子彈可以擊中敵人的飛機,因此玩家子彈敵人飛機是一對。
  2. 敵人飛機發出的子彈可以擊中玩家飛機,因此敵人子彈玩家飛機是一對。

碰撞分組設置

爲了使教程代碼清晰簡單,Shawn只設置了玩家子彈敵人飛機的碰撞,至於玩家飛機敵人飛機敵機子彈玩家飛機的碰撞就留給大家自行完成了(感覺是在繞口令…汗!)。

碰撞分組有了,設置子彈和敵機節點的Group屬性:
子彈Group爲my-bullet

敵機Group爲enemy

小結

使用 Cocos Creator 提供的碰撞系統:碰撞組件、碰撞分組、碰撞事件監聽,可以很方便地實現遊戲中的碰撞處理。

當碰撞產生時,所有關聯的碰撞對象都會收到碰撞回調通知,因此可以減少對其它模塊的依賴,儘可能各自處理自身的遊戲邏輯,比如:子彈碰撞只管自己的銷燬,它碰到誰都一樣(根據具體邏輯處理),如果敵機有盔甲防禦等複雜的機制,要以由敵機模塊處理傷害計算。

最後需要注意凹多邊形問題,儘可能使用矩形、圓型碰撞,如果必須使用多邊形碰撞,碰撞接觸面不要有凹陷。


歡迎關注我的公衆號,我們一起成長!

奎特爾星球

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章