斗地主滑動選擇卡牌的實現


最近想自己做一個斗地主游戲(使用cocoscreator + javascript),發現滑動選擇卡牌還有一點點麻煩呢,這里把實現分享下。

1、首先封裝卡牌 CardCtrl.js

  卡牌的touched屬性即為觸摸框選標記,selected屬性為觸摸結束所選擇卡牌的標記。其他的牌面花色什么的這里不做處理。

/**
 * Created by skyxu on 2018/11/1.
 * 
 * 卡牌組件
 */

cc.Class({
    extends: cc.Component,

    properties: {
        spSelected: cc.Node,
        touched: {
            default: false,
            notify(){
                this.spSelected.active = this.touched;
            }
        },
        selected: {
            default: false,
            notify(){
                if (this.selected){
                    this.node.y += 20;
                } else{
                    this.node.y -= 20;
                }
            }
        },
       
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad () {

    },

    start () {

    },

    // update (dt) {},
});

 

2、接着實現滑動選擇組件 DragSelect.js

  思路就是觸摸滑動時畫一個矩形,把和矩形有交集的卡牌都設為touched,觸摸結束時把屬性touched為true卡牌的selected屬性設為true即可。

需要注意的是,由於卡牌是有疊加的,選擇時要注意。我這里卡牌是右側的壓左側的,所以每次touchmvoe時,只選擇框選范圍內最右側的一張即可。主要分為3步:

  1. 判斷矩形范圍進行框選,在onTouchMove調用_checkSelectCard(beginPos,  endPos), 這里兩個參數都傳入當前的touchmove獲得的pos, 即畫一個最小的矩形,選擇范圍內最右側一張即可。

  2.處理框選范圍外的卡牌,在onTouchMove調用_checkSelectCardReverse(beginPos,  endPos), 這里兩個參數一個傳最初觸摸開始的點和當前觸摸的點。 這里需要注意的是,如果從右側向左側框選然后又退回到右側則要特別處理,一擔向右退回到當前卡牌的右側卡牌上時則要把當前卡牌的touched屬性設置為false(雖然矩形范圍還包括當前卡牌,但包括的部分為右側卡牌壓着的部分)

  3. 觸摸結束,touched屬性為true的卡牌即為所選,並重置touched為false

/**
 * Created by skyxu on 2018/11/1.
 * 
 * 滑動選擇卡牌組件
 * 把此組件拖放到卡牌根節點即可,卡牌根節點添加cc.Layout組件來自動布局
 * 
 */


cc.Class({
    extends: cc.Component,

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {},

    start () {
        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);

        this.cardsArr = this.node.getChildren();
        let card = this.cardsArr[0];
        // 指左側卡牌錨點到右側相鄰卡牌邊緣的距離
        this.CARD_DISTANCE = card.width*card.anchorX + this.node.getComponent(cc.Layout).spacingX;
        cc.log("CARD_DISTANCE: " + this.CARD_DISTANCE);
    },

    onTouchStart(event){
        let pos = event.getLocation();
        let beginPos = this._beginPos = this.node.convertToNodeSpaceAR(pos);
        this._checkSelectCard(beginPos, beginPos, true);
    },

    onTouchMove(event){
        let pos = event.getLocation();
        let movePos = this.node.convertToNodeSpaceAR(pos)
        // 這里確定是(movePos, movePos) 每次移動只選擇右側一張
        this._checkSelectCard(movePos, movePos);
        // 這里要傳入起點和結束點,獲取總的框取范圍
        this._checkSelectCardReverse(this._beginPos, movePos);
    },

    onTouchEnd(event){
        this._onSelectCardEnd();
    },

    _onSelectCardEnd(){
        for (let card of this.cardsArr){
            let ctrl = card.getComponent("CardCtrl");
            if (ctrl.touched){
                ctrl.selected = !ctrl.selected;
            }
            ctrl.touched = false;
        }
    },

    _checkSelectCard(beginPos, endPos, isBegin){
        let len = this.cardsArr.length;
        if (isBegin){
            for (let i=len-1; i>=0; i--){
                let card = this.cardsArr[i];
                if (cc.rectContainsPoint(card.getBoundingBox(), beginPos)){
                    card.getComponent('CardCtrl').touched = true;
                    return;
                }
            }
        } else{
            let w = Math.max(1, Math.abs(beginPos.x - endPos.x));
            let h = Math.max(1, Math.abs(beginPos.y - endPos.y));
            let x = Math.min(beginPos.x, endPos.x);
            let y = Math.min(beginPos.y, endPos.y);
            let touchRect = cc.rect(x, y, w, h);

            for (let i=len-1; i>=0; i--){
                let card = this.cardsArr[i];
                if (cc.rectIntersectsRect(card.getBoundingBox(), touchRect)){
                    card.getComponent('CardCtrl').touched = true;
                    return;
                }
            }
        }
    },

    _checkSelectCardReverse(beginPos, endPos){
        let p1 = beginPos.x < endPos.x ? beginPos : endPos;
        let w = Math.abs(beginPos.x - endPos.x);
        let h = Math.abs(beginPos.y - endPos.y);
        let rect = cc.rect(p1.x, p1.y, w, h);

        let len = this.cardsArr.length;
        for (let i=len-1; i>=0; i--){
            let card = this.cardsArr[i];
            if (!cc.rectIntersectsRect(card.getBoundingBox(), rect)){
                card.getComponent('CardCtrl').touched = false;
            }
        }

        // 從右向左框取然后又移動回右側則取消左側已經選擇的卡牌
        for (let i=0; i<len; i++){
            let card = this.cardsArr[i];
            if (p1.x - card.x >= this.CARD_DISTANCE){
                card.getComponent('CardCtrl').touched = false;
            }
        }
    }

    // update (dt) {},
});

 

3、測試

  在場景里添加一個卡牌根節點 cardPanel, 並為它添加cc.Layout組件(自動布局),然后把DragSelect.js組件拖放到cardPanel即可。

  效果圖如下

  

  Git鏈接:  https://github.com/sky068/dragSelectCards

 

  參考: https://blog.csdn.net/themagickeyjianan/article/details/39208463#commentBox

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM