昨天项目里面碰到了一个问题,spriteA的点击事件穿透了,导致spriteA没响应,而spriteA下面的spriteB响应了,其中spriteA和spriteB的优先级同为0。
我当时就有些奇怪,这是由于两者的ccTouchBegan的返回值为false,所以事件传递下去了。
要想touch事件不往下传递,1、CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true); 2、ccTouchBegan的返回值为true。
这里面还有一个关键点:在同一个layer中是后add的对象先接受touch响应,再根据其设置判断是否往下传递touch响应,而不是根据其depth来按顺序接受touch响应。
同理,在同一个scene中后add的layer先接受touch响应,再根据其设置判断是否往下传递touch响应,而不是根据该scene中各个layer的depth值来按顺序接受touch响应。
这解释可以结合上一篇文章里面的例子一起看,cocos2d-x中继承CCMenu定义自己的MyMenu,这个是解决优先级的问题 .
下面是我在网上看到别人的一些总结,也可以看看:
原文地址:Cocos2d中Touch事件总结:CCStandradTouch,CCTargetedTouch 作者:chase
在使用Touch事件时遇到过很多问题,这里总结一下。
首先,IOS为我们提供了以下的方法来得到并传递用户的输入:
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {}
(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {}
(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {}
(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {}
触摸信息可以直接从touches参数中获取
NSMutableSet *mutableTouches = [touches mutableCopy];
也可使用event参数来获取
NSSet *allTouches = [event allTouches];
Cocos2d用CCTouchDispatcher类分发从IOS获取的触摸事件。它有两种分发方式一种是CCStandardTouchDelegate,一种是CCTargetedTouchDelegate。前者将所有的Touch信息直接传递给实现该协议的对象,而后者则要求实现该代理的类一次只能处理一个事件,并且吃掉该事件,不再传播。
所以CCTargetedTouchDelegate这个协议针对单点触控,而CCStandardTouchDelegate则可以处理当前屏幕触摸的每个触摸点,好像最多是十个吧。CCLayer默认情况下如果设定接受Touch事件,是使用标准协议。
我们可以看到,在注册协议的时候分别对应这样的方式:
-(void) addStandardDelegate:(id<CCStandardTouchDelegate>) delegate priority:(int)priority;
-(void) addTargetedDelegate:(id<CCTargetedTouchDelegate>) delegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches;
他们的区别在swallowsTouches参数,它表示是否吃掉该事件,而且只在目标协议里有意义。我们来分析各个协议的工作机理:
Standard这套协议,他会按照优先级给每个层排序。然后把touch按照顺序分别传进去,也就是说从上到下的所有层只要开启了self.istouchenabled = YES 那么他们都会收到touch,而且不可以吃掉该事件。测试显示即使上面一层相应了该事件,它仍然会传递到下一层。
targeted这套协议只支持单点触控,即使是多点触控也当单点触控来用,但是返回的UITouch 就不知道是哪个了。他的好处是有swallow选项,即可判断是否继续传递 touch,而且,他的cctouchbegan函数是个bool值,如果你不返回一个yes的话,后面的 move 和 ended 都不会执行,如果要使用该协议,要在layer中手动设定代理:addStandardDelegate。因为CCLayer内部只注册标准代理。
我们的问题就来了,Standard协议无法吃掉事件,也许多个层都会相应的时候会出问题,而研究target协议实现的源码,也可以发现其实吃掉一个事件很简单,只要在Touch的集合中执行removeObject方法即可。
CCMenu继承了CCLayer,但是它注册的是targeted协议,所以我们很少发现CCMenu的混乱,因为它会将touch吃掉。