CreatorPrimer | 物理小遊戲(碰撞事件監聽)

繼續物理小遊戲,我們先回顧一下CreatorPrimer倉庫中提供的五個組件腳本:

通用物理組件

使用這5個組件腳本,可以構建非常有趣的物理小遊戲,下面我們對這5個自定義組件做一個簡單介紹:

  1. PhysicsManager: 物理引擎管理器,使用它無需編程即可開啓\關閉物理引擎,並提供剛體的着色調試開關。

物理引擎管理器.png
2. PhysicsVelocity: 物理速度控制組件,提供了一個force函數方便使用cc.Button在編輯器中調用,爲剛體施加外力。
3. PhysicsColliderNotification: 物理碰撞通知組件,使用它可以讓非物理組件或腳本能收到物理碰撞事件。
4. ScoreNotificationHandle:得分通知處理組件,該組件監聽PhysicsColliderNotification發出的事件通知,更新Label文本。
5. ScoreVerifyNotificationHandle:帶驗證功能的得分通知處理組件。

我們今天的重點是PhysicsColliderNotification組件的實現。

1. 開啓剛體碰撞監聽

開啓碰撞接觸監聽

PhysicsColliderNotification組件功能是監聽剛體的碰撞事件,因此它需要依賴剛體組件(RigidBody),同時在運行時自動開啓剛體的enabledContactListener屬性。

cc.Class({
    //依賴剛體組件
    editor: CC_EDITOR && {
        requireComponent: cc.RigidBody,
    },
    extends: cc.Component,
    ...
    start () {
        //獲取剛體組件
        let rigidBody = this.getComponent(cc.RigidBody);
        //開啓碰撞接觸監聽
        rigidBody.enabledContactListener = true;
    },
   ...
});

最初,有網友在使用Shawn提供的腳本發現時有不靈,發現是因爲未開啓剛體碰撞監聽開關的原故,因此重構時增加了RigidBody的依賴,同時在組件start生命週期函數中開啓剛體的enabledContactListener屬性,增強使用體驗,減少意外發生。

2. 碰撞事件監聽

在籃框節點上開啓了剛體的碰撞監聽,就可以此節點的任意組件代碼上編寫碰撞監聽處理函數了,我們看一下PhysicsColliderNotification碰撞處理函數的實現細節:

/**
 * 物理碰撞通知組件,要以讓非物理組件或腳本能收到物理碰撞事件
 */
cc.Class({
    ...
    extends: cc.Component,

    properties: {
       notificationName:'',
       _p0: null,
       _p1: null,
    },

    /**
     * 只在兩個碰撞體開始接觸時被調用一次
     */
    onBeginContact(contact, selfCollider, otherCollider) {
        cc.log(otherCollider.node.name);
        this._p0 = otherCollider.node.position;
    },

    /**
     * 只在兩個碰撞體結束接觸時被調用一次
     */
    onEndContact: function (contact, selfCollider, otherCollider) {
        this._p1 = otherCollider.node.position;
        if (this.notificationName) {
            cc.director.emit(this.notificationName, contact, this._p0, this._p1);
        }
    },
});

不知道大家是否還記得,在籃框的碰撞組件中需要設置Sensor屬性,它可以使用節點不產生物理碰撞效果,讓其它動態剛體可以穿透它,但能監聽物理碰撞事件,請看下圖:

開啓Sensor屬性

開啓了Sensor屬性,通過引擎提供的onBeginContact、onEndContact兩個事件監聽函數獲取籃球剛體的座標點,識別籃球是從上向下投進的,還是從下向上進框的,從而實現正確記分。

組件中的_p0、_p1變量就是剛體碰撞時的開始點和結束點,在onEndContact事件中通過cc.director.emit將自定義事件、碰撞開始\結束座標點廣播出去。

3. 自定義事件

爲什麼不直接在剛體節點上直接處理得分呢?要使用cc.director.emit中轉一下呢?因爲剛體碰撞事件,只能在剛體節點上才能監聽到,得分的表現使用的是一個Label組件,如果將代碼寫在一堆,那這個PhysicsColliderNotification組件做的事情就不只一件,而且太過具體,而且設計多個對象,導致通用性會大大降低。

使用cc.director.emit(‘xxx’)將廣播一個事件出去,在任意腳本中使用cc.director.on(‘xxx’)接收事件,不論是更新得分,還是處理遊戲的流程、特效等等,會更加的靈活可變,可以讓策劃或設計師發揮出更多的創作空間。

cc.Director是繼承成自cc.EventTarget,cc.director是一個全局變量,因此使用cc.director.emit、cc.director.on實現事件的訂閱、發佈非常簡單,是實現組件間的通信的一種非常方便的方案。

很多人都使用過cc.Node.emit、cc.Node.on來發送和監聽事件,唯一不方便的就是你需要先獲取發送事件的節點對象。相信還有人懷念Cocos2d-x中的CCNotificationCenter,完全可以使用cc.EventTarget實例化一個全局的EventTarget對象來模擬,實現相同的效果。

通過事件可以方便解耦對象之間的依賴,用一個通俗點的說法就是:“你不要打電話給我,我會打電話給你!”。打電話首先需要電話號碼就是事件名稱,說這句話的人就是EventTarget對象,聽話的人就是遞交電話號碼(事件名)、接聽電話的程序同學。

4. 小結

本篇介紹了PhysicsColliderNotification組件的實現,全是代碼和邏輯,不能照顧到非程序員同學,還請包涵。

監聽物理碰撞一定要開啓剛體的enabledContactListener屬性,在onBeginContact、onEndContact事件中獲取剛體的位置以識別剛體的運行方向。同時使用cc.director.emit將事件、座標點廣播出去,在關心的地方做對應的邏輯處理。

目前源碼已經合併到CreatorPrimer倉庫主幹,歡迎把玩,提出你的建議!
源碼地址:https://github.com/ShawnZhang2015/CreatorPrimer


如果覺得公衆號上的文章對您或您身邊的朋友有幫助,請分享給他,願我們一起成長!

奎特爾星球

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