cocos2d Touch处理摘抄总结

Refer to: http://www.cnblogs.com/zeping/archive/2011/04/09/2010787.html

Refer to: http://blog.csdn.net/crayondeng/article/details/9961665

实现原理

一,iPhone OS 提供了关亍触摸(Touch)的以下 4 个事件响应凼数:

 (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 {}

1, 由两种方式获得事件:

(1) touches 参数:

NSMutableSet *mutableTouches = [touches mutableCopy];

(2)也可以通过 event 参数获得:

NSSet *allTouches = [event allTouches];

2,依次处理每一个触摸点 通过[allTouches count]来判断是多触点还是单触点,获叏第一个 触摸点方法:

UITouch *touch = [[allTouches allObjects] objectAtIndex:0];

获取第二个触摸点:

UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];

第三、第四...多点触摸以此类推。

3,针对每个触摸点的处理

通过以下凼数考察每个触摸点是单击还是双击:

[touch tapCount]



二,Cocos2D 的事件处理机制

1,接管:从系统 iPhoneOS 的标准UIView 获得触摸输入。

     为了便于针对 OpenGL ES 的编程,苹果公司提供了派生于类 UIView 的类 EAGLView 来实现 OpenGL 输出支持。

(参考 Cocos2d 目录 cocos2d\Support 下的文件:EAGLView. EAGLView.m)

Cocos2d-iPhone 的主控类 Director 通过下面的凼数实现了 Cocos2d-iPhone 与iPhone 应用程序主窗口之间的联系:

EAGLView *view = [director openGLView];

该方法的具体实现

由CC_DIRECTOR_INIT();实例化CCDirector的内置变量openGLView, 然后调用openGLView方法取得

(当然也由其他的方法实现这绑定[[Director sharedDirector] attachInView:view];)

      又由于EAGLView继承了UIView,固也继承了Touch事件的4个方法touchesBegan等

      为了接管iphone中的事件。

      首先,定义了一个接管的协议。

@protocol EAGLTouchDelegate <NSObject>

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

@end

同时,在EAGLView的一个成员变量id< EAGLTouchDelegate > touchDelegate_

CCTouchDispatcher.h实现了EAGLTouchDelegate协议


整合部分:我门在CCDirector.h文件的-(BOOL)initOpenGLViewWithView:(UIView *)view withFrame:(CGRect)rect方法中,我们会发现


// 设定用户输入代理对象。单例 对象 sharedDispatcher 在此引入。

[openGLView_ setTouchDelegate: [TouchDispatcher sharedDispatcher]];

...

// 通过添加子视图将 UIView 转化为直接支持 OpneGL ES 输出。 [view addSubview:openGLView_];


于是在,从UIView继承的四个方法中,调用协议的方法

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

if(touchDelegate_)

{

[touchDelegate_ touchesBegan:touches withEvent:event];

}

}


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

if(touchDelegate_)

{

[touchDelegate_ touchesMoved:touches withEvent:event];

}

}


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

if(touchDelegate_)

{

[touchDelegate_ touchesEnded:touches withEvent:event];

}

}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

{

if(touchDelegate_)

{

[touchDelegate_ touchesCancelled:touches withEvent:event];

}

}

这样就实现了CCTouchDispatcher的全面接管了,如果视线可以关 注CCTouchDispatcher的实现了


2,分发:按照预先定义好的逻辑分収给各种注册对象。

我们发现touchDelegate_的四个方法 都是调用

-(void) touches:(NSSet*)touches withEvent:(UIEvent*)event withTouchType:(unsigned int)idx;

该方法首先处理TargetedTouchDelegate协议,

方法由:

@protocol CCTargetedTouchDelegate <NSObject>


/** Return YES to claim the touch.

 @since v0.8

 */

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event;

@optional

// touch updates:

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event;

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event;

- (void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event;

@end


后StandardTouchDelegate协议,

@protocol CCStandardTouchDelegate <NSObject>

@optional

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

@end

判断touches中哪些是第一个协议,哪个是第二个协议,主要看- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event;这个方法,在CCTargetedTouchDelegate协议中是必须 的实现的,如果是该协议的,并返回YES,则继续

-(void) touches:(NSSet*)touches withEvent:(UIEvent*)event withTouchType:(unsigned int)idx的方法

并由CCTouchHandler类实现具体的操作。


3,处理:注册对象乊间如何协调响应用户的输入。

CCTouchDispatcher的内部成员

NSMutableArray *targetedHandlers;

NSMutableArray *standardHandlers;

当用户设置自定义的Layer中的isTouchEnabled = YES时,会调用Layer中的方法

-(void) setIsTouchEnabled:(BOOL)enabled

{

if( isTouchEnabled != enabled ) 

{

isTouchEnabled = enabled;

if( isRunning_ 

{

if( enabled )

[self registerWithTouchDispatcher];

else

[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];

}

}

}

[self registerWithTouchDispatcher];

一般该语句的意思是注册到StandardTouchDelegate, 如果是MenuItem Layer则注册到TargetTouchDelegate中,具体的操作也就是将Layer实例放入到如下对应的NSMutableArray 中

NSMutableArray *targetedHandlers;

NSMutableArray *standardHandlers;


实际使用方法

0、默认情况下CCLayer都是没有启动触摸事件的,所以需要在初始化函数中  this->setTouchEnabled(true); 启用触摸事件处理。

1、首先需要在  registerWithTouchDispatcher() 方法中注册处理触摸事件的机制。

CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this, 0);

CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true); 

CCLayer的默认registerWithTouchDispatcher实现是注册为CCStandardTouchDelegate, 另外,在调用的时候不能自己调用registerWithTouchDispatcher,而应该调用

 this->setTouchEnabled(true);

2、实现回调函数

在两种实现机制中都分别指定了处理触摸事件的回调函数,所以用户在注册了不同的处理机制后,就需要实现响应的回调函数。


(1)Standard Touch

CCStandardTouchDelegate包含四个回调函数,分别如下:

CCStandardTouchDelegate 默认事件
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); 处理按下事件
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent); 处理按下并移动事件
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent); 处理松开事件
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent); 处理打断事件
①这些回调函数中的参数,接收到的touch触摸是CCSet类型,说明是多点的touch。那么就可以实现多点触摸的处理了。如果要想实现多点触摸,那么首先需要在

[cpp]  view plain copy
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

方法中设置:

[cpp]  view plain copy
  1. //设置多点触摸  
  2.     [__glView setMultipleTouchEnabled:YES];  

那么在回调函数中就可以进行多点触摸的处理了:

[cpp]  view plain copy
  1. void HelloWorld::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)  
  2. {  
  3.     CCLog("tap count = %d",pTouches->count());  
  4.       
  5.     for (CCSetIterator iterTouch = pTouches->begin(); iterTouch != pTouches->end(); iterTouch ++) {  
  6.           
  7.         CCTouch *pCurTouch = (CCTouch*)(*iterTouch);  
  8.         CCPoint point = pCurTouch->getLocation();  
  9.         CCLog("%f,%f",point.x,point.y);  
  10.     }  
  11. }  

(2)Target Touch

CCTargetedTouchDelegate 包含下面四个回调函数:

CCTargetedTouchDelegate
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); 处理用户按下事件,true表示继续处理, 否则false.
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); 处理按下并移动事件
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); 处理松开事件
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); 处理打断事件
CCTargetedTouchDelegate 和 CCStandardTouchDelegate 有很大的区别。

第一,CCTargetedTouchDelegate 回调里的参数接收的不是Touch事件的集合(CCSet),而是单个的Touch事件,cocos2d-x会将多点触摸拆散成单个的Touch事件再进行回调。即事件参数不再是集合,而是一次只传入一个触摸点。


第二,用户必须实现ccTouchBegan 函数,且如果某个用户按下消息需要继续跟踪,则ccTouchBegin返回true, 否则,ccTouchMoved,ccTouchEnded等接口不会被调用到。即ccTouchBegan方法返回一个布尔值,表示声明是否要捕捉这个触摸点,只有在此方法中捕捉到的触摸点才会继续引发其他3个事件,否则此触摸点的其他事件都会被忽略。


第三,注意到

[cpp]  view plain copy
  1. void CCTouchDispatcher::addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches)  

在addTargetedDelegate方法中,前两个参数分别对应触摸接收对象和优先级,其中优先级是一个整型参数,值越低,则优先级越高,也就越早获得触摸事件。通常,为了获得较高的优先级,可以将其指定为负数。

其中的第三个参数较为有趣,表明了是否"吞噬"一个触摸,如果设置为true,一个触摸一旦被捕捉,那么所有优先级更低的接收对象都无法接收到触摸。即用户在注册TargetTouchDelegate的时候可以设置bSwallowsTouches标识,若某个TargetTouchDelegate将该标识设为true,且需要处理某个Touch事件(ccTouchBegan

返回true),则调到该Delegate之后cocos2d-x不会将Touch消息发送给其他的TargetTouchDelegate和StandardTouchDelegate。

例如:CCMenu就是一个会"吞噬"且优先级为-128的触摸接收器,由于它的优先级很高,所以菜单按钮总能获得触摸响应。


二、touch 事件分发顺序

cocos2d-x 首先派发事件给CCTargetedTouchDelegate, 再派发事件给CCStandardTouchDelegate。对于相同类型的TouchDelegate, 则是根据注册的优先级

来确定派发先后顺序。如果优先级也一样,则按照注册的顺序派发事件。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值