cocos creator Touch事件应用(触控选择多个子节点)

Posted 追极

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cocos creator Touch事件应用(触控选择多个子节点)相关的知识,希望对你有一定的参考价值。

最近参与了cocos creator的研究,开发小游戏,结果被一个事件坑得不行不行的。现在终于解决了,分享给大家。

 

原理

1.触控事件是针对节点的

2.触控事件的冒泡,是一级一级往上冒泡,中间可以阻止冒泡

3.父节点不响应触控事件,注意看父节点的位置、大小等,如果触点位置不在父节点区域内肯定不能触发touch事件了,父节点大小为0肯定也不会触发touch事件了!

4.触控事件往祖先节点冒泡,祖先节点是否会检测触点是否在自己区域内,由子节点是否监听了touch事件有关。子监听了,父就不会检测区域是否包含触点,始终响应触控事件,没有监听,则会检测是否包含触点,包含才会响应触控事件!(这点与官网文档不一致,我亲测出来的结果)

5.触控位置是绝对坐标,相对于整个canvas,节点位置相对于父节点,相对位置可以与绝对坐标相互转化

6.节点是否被触控到,touch start事件可以肯定被触摸到,但是一个节点触摸到必须等待其结束,另一个节点才能响应touch事件

7.判断是否框选中,根据坐标计算相互交叉即是选中。就是说我从触控起点->触控终点 构成的矩形区域,与节点的矩形存在重叠,就是被框选。本例中,采用比较粗略的算法实现,根据横坐标的范围是否包含子节点的横坐标判断是否选中。

8.计算某个数值是否在某一范围内,首先计算出范围的最大值、最小值,然后作比较即可。

 

核心代码

cc.Class({
    extends: cc.Component,

    properties: {
        // foo: {
        //    default: null,      // The default value will be used only when the component attaching
        //                           to a node for the first time
        //    url: cc.Texture2D,  // optional, default is typeof default
        //    serializable: true, // optional, default is true
        //    visible: true,      // optional, default is true
        //    displayName: \'Foo\', // optional
        //    readonly: false,    // optional, default is false
        // },
        // ...
            poker:{
                default:null,
                type:cc.Node
            },
            cardMask:{
                default:null,
                type: cc.Prefab
            }
    },

    // use this for initialization
    onLoad: function () {
            
            //
            this.cards = this.poker.children;

            //牌初始位置
            this.cardInitY = this.cards[0].y;

            //触摸选择到的牌
            this.touchedCards = [];

            //选中的牌
            this.selectedCards = [];

            console.info(this.cards);
        },
        
        start: function () {
            // this.cards = this.poker.children;
            // console.info(this.cards);
            
            this.addTouchEvent();
        },

        /**
         * 添加事件
         */
        addTouchEvent:function(){

            //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
            this.poker.on(cc.Node.EventType.TOUCH_START, function (event) {
                console.log(\'poker TOUCH_START\');
                
                //
                var card = event.target;
                
                //起始触摸位置(和第一张card一样,相对于poker的位置)
                this.touchStartLocation = this.cards[0].convertTouchToNodeSpace(event);
                console.log(\'touch start Location:\'+ JSON.stringify(this.touchStartLocation));
                
                //计算牌位置
                var index = 0;
                for(var i=0;i<this.cards.length;i++){
                    var c = this.cards[i];
                  if(c.name == card.name){
                        index = i;
                        break;
                    }
                }

                //暂存第一次触摸到的牌
                var touchedCard = {
                    index:index,
                    card:card
                };
                this.firstTouchedCard = touchedCard;
                //暂存
                this.pushTouchedCards(touchedCard.index,touchedCard.card);

            }, this);
        
            //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
            this.poker.on(cc.Node.EventType.TOUCH_MOVE, function (event) {
                console.log(\'poker TOUCH_MOVE\');
                //先清除原先触摸到的牌
                this.clearTouchedCards();
                //保存第一张牌
                this.pushTouchedCards(this.firstTouchedCard.index,this.firstTouchedCard.card);

                //触摸点转换为card节点坐标
                var nodeLocation = this.cards[0].convertTouchToNodeSpace(event);
                console.log(\'touch nodeLocation:\'+ JSON.stringify(nodeLocation));
                var x = nodeLocation.x;
                var y = nodeLocation.y; 

                //找到当前选中的牌
                var currentCard = null;
                for(var i=0;i< this.cards.length;i++){
                    var card = this.cards[i];
                    var cardX = card.x;
                    var cardY = card.y;
                    console.log(\'card x=\'+cardX+\',y=\'+cardY);


                    //某张牌范围包括了鼠标位置,选中此牌与触摸开头的所有牌
                    var cardWidth = i==5 ? card.width:19;
                    var cardHeight = card.height;
                    if(cardX<=x && x <= cardX+cardWidth && cardY<=y && y<= cardY+cardHeight){
                        currentCard = card;
                
                        //暂存触摸到的牌
                        this.pushTouchedCards(i,card);
                        
                        break;
                    }
                }
                
                //添加开头与此牌直接的所有牌
                var startTouchLocation = this.touchStartLocation;
                for(var i=0;i< this.cards.length;i++){
                    var card = this.cards[i];
                    var cardX = card.x;
                    //框选的范围包括了的牌
                    var min,max;
                    if(startTouchLocation.x < nodeLocation.x){
                        min = startTouchLocation.x;
                        max = nodeLocation.x;
                    }else{
                        min = nodeLocation.x;
                        max = startTouchLocation.x;
                    }
                    console.log(\'min=\'+min+\', max=\'+max);

                    if(min <= cardX && cardX <= max){
                        //暂存触摸到的牌
                        this.pushTouchedCards(i,card);
                    }
                }
                

            }, this);
        
        //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
        this.poker.on(cc.Node.EventType.TOUCH_END, function (event) {
            console.log(\'poker TOUCH_END\');
            this.doSelectCard();
        }, this);
        
        //父节点监听touch事件(直接子节点必须注册同样的事件方能触发)
        this.poker.on(cc.Node.EventType.TOUCH_CANCEL, function (event) {
            console.log(\'poker TOUCH_CANCEL\');
            this.doSelectCard();
        }, this);
        
        //给所有的牌注册事件,会自动冒泡到poker节点
        for(var i=0;i< this.cards.length;i++){
            var cards = this.cards;
            //闭包传递i值
            (function(i){
                var card = cards[i];
                card.on(cc.Node.EventType.TOUCH_START, function (event) {
                    console.log(\'card TOUCH_START\');
                }, card);
                
                card.on(cc.Node.EventType.TOUCH_MOVE, function (event) {
                    console.log(\'card TOUCH_MOVE\');
                }, card);

                card.on(cc.Node.EventType.TOUCH_END, function (event) {
                    console.log(\'card TOUCH_END\');
                }, card);
    
                card.on(cc.Node.EventType.TOUCH_CANCEL, function (event) {
                    console.log(\'card TOUCH_CANCEL\');
                }, card);

            
            })(i)
            
        }
        
    },

    /**
     * 暂存触摸到的牌
     */
    pushTouchedCards:function(index,card){
        //构造牌对象
        var cardObj = {
            index:index,
            name:card.name,
            isSelected:card.y==this.cardInitY?false:true //高度不一样,表示选中
        };
        
        //防止重复添加
        var existCard = this.touchedCards.find(function(obj){
            if(obj.name == card.name){
                return obj;
            }else{
                return null;
            }
        });
        if(!existCard){
            //添加暂存
            this.touchedCards.push(cardObj);

            //包含提示
            this.addCardMask(card);
        }
    },

    /**
     * 清除原先暂存的触摸到的牌
     */
    clearTouchedCards:function(){
        for(var i=0;i<this.touchedCards.length;i++){
            var cardIndex = this.touchedCards[i].index;
            var card = this.cards[cardIndex];
            card.removeChild(card.children[0]);
        }
        this.touchedCards = [];
    },

    /**
     * 选择牌
     */
    doSelectCard:function(){
        this.selectedCards = [];

        console.log(this.touchedCards);

        //改变牌状态
        for(var i = 0; i< this.touchedCards.length;i++){
            var cardObj = this.touchedCards[i];
            var card = this.cards[cardObj.index];
            if(cardObj.isSelected){ //如果是选中改为不选中
                card.y = card.y - 30;
            }else{ //不选中改为选中状态
                card.y = card.y + 30;
            }
        }

        //重置
        this.clearTouchedCards();

        //显示选中的牌
        this.showSelectedCards();
    },

    /**
     * 包含牌遮罩
     */
    addCardMask:function(card){
        var cardMask = cc.instantiate(this.cardMask);
        cardMask.setPosition(cc.p(0, 0));
        card.addChild(cardMask);
     },

    /**
    * 显示选中的牌
    */
    showSelectedCards:function(){
        this.selectedCards = [];
        for(var i=0;i< this.cards.length;i++){
            var card = this.cards[i];
            var isSelected = card.y==this.cardInitY?false:true;
            if(isSelected){
                this.selectedCards.push(card.name);
            }
        }
        //输出
        console.info("selected cards is: "+ JSON.stringify(this.selectedCards));
    },

    
    // called every frame, uncomment this function to activate update callback
    // update: function (dt) {

    // },
});

 

效果

 

以上是关于cocos creator Touch事件应用(触控选择多个子节点)的主要内容,如果未能解决你的问题,请参考以下文章

Cocos Creator 3.0 基础——事件系统

Cocos Creator 3.0 基础——事件系统

Cocos Creator Touch_End的触发条件陷阱

Cocos Creator Touch_End的触发条件陷阱

cocos creator 判断滑动方向

Cocos Creator更改底层,点击节点获取路径