CocosCreator之控制遊戲觸點數量

KUOKUO眾享發表於2020-11-08

摘要

在一部分遊戲開發中,多點觸控並不是被期望的。官方在 v2.3.0 版本時提供了單點觸控的開關,但是並不能指定觸點數量,且舊版本沒法使用,那麼可不可以實現這一功能呢?

正文

測試版本

CocosCreator 版本 2.0.5
CocosCreator 版本 2.1.2
CocosCreator 版本 2.3.4
CocosCreator 版本 2.4.2

思維過程

控制開關 cc.macro.ENABLE_MULTI_TOUCH 是新版才有的,想相容舊版本還是要去更根源的地方找,跑到原始碼裡先看看觸控事件最開始在哪裡分發的!首先想到的是,既然在瀏覽器端可以進行點選,必然會走註冊事件的方法,去原始碼裡搜一下 window.addEventListener,看了一下,果然有個翻譯過來像輸入的指令碼 CCInputManager.js。然後在這個指令碼中搜一下 touchstart 果然找到了對應的方法:

/**
 * @method handleTouchesBegin
 * @param {Array} touches
 */
handleTouchesBegin (touches) {
    let selTouch, index, curTouch, touchID,
        handleTouches = [], locTouchIntDict = this._touchesIntegerDict,
        now = sys.now();

    for (let i = 0, len = touches.length; i < len; i ++) {
        selTouch = touches[i];
        touchID = selTouch.getID();
        index = locTouchIntDict[touchID];

        if (index == null) {
            let unusedIndex = this._getUnUsedIndex();
            if (unusedIndex === -1) {
                cc.logID(2300, unusedIndex);
                continue;
            }

            //curTouch = this._touches[unusedIndex] = selTouch;
            curTouch = this._touches[unusedIndex] = new cc.Touch(selTouch._point.x, selTouch._point.y, selTouch.getID());
            curTouch._lastModified = now;
            curTouch._setPrevPoint(selTouch._prevPoint);
            locTouchIntDict[touchID] = unusedIndex;
            handleTouches.push(curTouch);
        }
    }

    if (handleTouches.length > 0) {
        this._glView._convertTouchesWithScale(handleTouches);
        let touchEvent = new cc.Event.EventTouch(handleTouches);
        touchEvent._eventCode = cc.Event.EventTouch.BEGAN;
        eventManager.dispatchEvent(touchEvent);
    }
}

程式碼的邏輯是處理傳入的多個觸點,為每個觸點分配一個未使用的 id,排好序後分發出去,我們想控制觸點的數量,那麼是不是可以從獲取 未分配的 id 入手呢,我最多允許分配固定數量的 ID 是不是就可以控制最大觸點數量?看下分配的方法:

_getUnUsedIndex () {
    let temp = this._indexBitsUsed;
    let now = cc.sys.now();
    for (let i = 0; i < this._maxTouches; i++) {
        if (!(temp & 0x00000001)) {
            this._indexBitsUsed |= (1 << i);
            return i;
        }
        else {
            let touch = this._touches[i];
            if (now - touch._lastModified > TOUCH_TIMEOUT) {
                this._removeUsedIndexBit(i);
                delete this._touchesIntegerDict[touch.getID()];
                return i;
            }
        }
        temp >>= 1;
    }
    // all bits are used
    return -1;
}

分配時有個 this._touches 陣列儲存這些觸點,經過一次 For 迴圈分配 ID,最多分配 this._maxTouches 個 ID。這樣就明白了,乾脆改掉 _maxTouches 就能限制分配的數量了,先改成一,然後拿手機掃碼試試。成了!再搞成 0 試試,果然觸控失效了!!!完美!

更好的實現

魔改下引擎後,換專案或者引擎版本無法做到複用,有沒有更好的辦法呢?當然,外掛指令碼就能實現這個需求,在 CocosCreator 中指令碼執行順序為:Cocos2d 引擎最先執行,然後是外掛指令碼(有多個的話按專案中的路徑字母順序依次載入),最後才是我們寫的普通指令碼(打包後只有一個檔案,內部按 require 的依賴順序依次初始化)。

那就將這個修改寫進 k-cocos.js 擴充套件指令碼中,宣告一個方法掛載到 cc 上吧,CCInputManager.js 指令碼最末尾有著匯出的邏輯:

module.exports = cc.internal.inputManager = inputManager;

不同的版本還不一樣,新版是 cc.internal,比較舊的版本是 _cc.inputManager,那就只好做下相容處理。

// 觸點數量控制
cc.kMultTouch = function (count) {
    // 2.3.0 版本以上
    if (cc.internal && cc.internal.inputManager) {
        cc.internal.inputManager._maxTouches = count;
        return;
    }
    // 低版本
    if (_cc && _cc.inputManager) {
        _cc.inputManager._maxTouches = count;
    }
    // 低版本相容 QQ_PLAY 的一段邏輯
    if (CC_QQPLAY && BK && BK.inputManager) {
        BK.inputManager._maxTouches = count;
    }
}

結語

擴充套件指令碼已經開源,實現了遊戲速率控制、全域性觸點數量控制、也擴充套件了節點的一些屬性和方法,還有許多想法沒加進去,歡迎大家提建議、給點個星星 Star,歡迎加入討論 QQ 群:1085201157

GitHub地址: https://github.com/KuoKuo666/k-cocos

個人網站:www.kuokuo666.com

2020!我們一起進步!O(∩_∩)O~~

相關文章