【Cocos Creator 實戰】07 - 如何讓拼圖回到原位(優化自動吸附規則)

繼續繼續。

上一篇地址:【Cocos Creator 實戰】06 - 如何給拼圖遊戲添加計時器

概覽

主要內容

在上一篇結尾的時候,我們引用了以爲同學的話:

在拼圖遊戲中,如果幾塊拼圖都重合在一個錨點,感覺會降低遊戲體驗。可是如何做到移動圖片至已經存在圖片的錨點時,將後來的圖片彈到其他區域(也就是說有圖片的錨點不能吸附新的圖片)。這種功能該怎麼實現呢?

今天我們就來解決這個問題。

來看看這個問題修改之前的效果:
在這裏插入圖片描述

再來看看修改之後的效果:

在這裏插入圖片描述

可以看到,效果還是很明顯的。

具體的內容大家可以在下面的演示地址中體驗。

項目資源

推薦大家先把項目 clone 到本地,然後參考着代碼來看本篇文章。
我的每篇文章會對應一個分支,大家直接看對應的分支就可以,master 對應的是最新的內容,會整合各個分支。
演示地址也是對應每篇文章獨立部署的,直接點擊前往即可。

開搞

今天我們修改的內容比較簡單,總共就改了一個文件。

原理

咱們先想一下,如果是你來設計,你準備怎麼實現上面的功能。

能用白話把邏輯描述清楚就行。

這裏停頓 30s。

這裏停頓 30s。

這裏停頓 30s。

我來說一下我設計的實現原理:

1、拿起圖片的時候記錄下位置

2、放下圖片的時候判斷,將要自動吸附(移動)到的位置上是否已經有其他圖片

  • 如果有,那剛剛放下的圖片自動移動到拿起時的位置(歸位)
  • 如果沒有,那執行自動吸附操作

沒了。

簡單吧。

來看看代碼實現。

核心代碼

修改 item-manager.js 文件中的 __moveStart 方法:

    __moveStart(node) {
        console.info('start');

        let itemManager = node.parent.getComponent('item-manager');
        // 在這裏記錄拿起時圖片的位置
        itemManager.itemStartPos = cc.v2({x: node.position.x, y: node.position.y});
        itemManager.maxIndex++;
        node.zIndex = itemManager.maxIndex;

        cc.loader.loadRes('sound/pick', cc.AudioClip, function (err, clip) {
            cc.audioEngine.playEffect(clip, false);
        });
    },

修改 item-manager.js 文件中的 __adsorption 方法:

    __adsorption(node) {
        let picHeight = node.height;
        let picWidth = node.width;
        let nodeVec = cc.v2({x: node.position.x, y: node.position.y});
        let conditions = [
            {x: picWidth, y: 0},
            {x: (-1) * picWidth, y: 0},
            {x: 0, y: picHeight},
            {x: 0, y: (-1) * picHeight},
        ];

        for (let i = 0; i < this.items.length; i++) {
            let itemNode = this.items[i].node;
            let itemPos = itemNode.position;
            let isMoved = false;

            for (let j = 0; j < conditions.length; j++) {
                let con = conditions[j];
                let targetVec = cc.v2({
                    x: itemPos.x + con.x,
                    y: itemPos.y + con.y
                });
                let distance = targetVec.sub(nodeVec).mag();
                if (distance > 100) continue;

                isMoved = true;

                // 目標位置上已經有其他節點
                if (this.__isPosHasItem(node, targetVec)) {
                    let action = cc.moveTo(0.1, this.itemStartPos);
                    node.runAction(action);
                }
                // 目標位置上沒有其他節點
                else {
                    let finished = cc.callFunc(this.__checkWin, this);
                    let action = cc.moveTo(0.1, targetVec);
                    let seq = cc.sequence(action, finished);
                    node.runAction(seq);
                }

                break;
            }

            if (!isMoved) continue;
            console.info('自動吸附條件成立!!!!');
            break;
        }
    },

item-manager.js 文件中增加一個 __isPosHasItem 方法,用於判斷目標位置上是否已經有其他圖片:

    __isPosHasItem(node, targetVec) {
        for (let i = 0; i < this.items.length; i++) {
            let item = this.items[i];
            if (item.node._id == node._id) continue;
            if (Math.abs(item.node.position.x - targetVec.x) > 1) continue;
            if (Math.abs(item.node.position.y - targetVec.y) > 1) continue;

            return true;
        }

        return false;
    }

簡單吧。

只要想清楚了原理,實現起來都很簡單。

這裏多說一嘴 __isPosHasItem 方法中的第四行:

if (item.node._id == node._id) continue;

這裏判斷了一下,這個節點是不是我們正在移動的節點,因爲我們正在移動的節點有可能剛好移動到了目標吸附位置,那你再彈回去,就尷尬了不是。

下面的兩行代碼:

if (Math.abs(item.node.position.x - targetVec.x) > 1) continue;
if (Math.abs(item.node.position.y - targetVec.y) > 1) continue;

這裏之所以沒有使用全等,是因爲兩個位置之間的差距極小極小(但不是0),你自己跑一下就知道了,所以我用了一個範圍:只要在 1個像素 範圍內,都算重疊。

大家可以想一下,我這裏使用的是座標位置計算的,還可以使用什麼方法?

我們在之前第四篇文章 【Cocos Creator 實戰】04 - 如何給拼圖加上吸附效果 中學習的計算兩個節點間的距離的方法是不是也可以?

好了,這回真沒了。

總結

知識點

1、像素點與圖片位置計算

下一步

這篇文章內容很簡單,也很好理解,希望大家不要侷限於我使用的方法,自己思考一下,不妨將你的方案發出來,大家討論一下。

下一篇地址:【Cocos Creator 實戰】08 - 如何讓拼圖遊戲暫停/繼續

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