• 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.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) {
    
        // },
    });

    效果

  • 相关阅读:
    Ubuntu设置文件默认打开方式
    车险与费用计算(仅做参考)
    房贷计算
    PHP敏感词处理
    记一次,接口pending
    layer confirm确认框,多个按钮
    crontab vim 模式
    git指定迁出目录
    mysql树形结构
    Kubeflow实战: 入门介绍与部署实践
  • 原文地址:https://www.cnblogs.com/hdwang/p/7498858.html
Copyright © 2020-2023  润新知