在智能手机中,触屏操作占有很重要的位置,尤其是多点触摸技术的兴起,使得触屏操作在游戏中更广泛的使用,使操作方式更加丰富。在Cocos2D-x中,继承自触屏代理协议CCTouchDelegate的布景层类CCLayer可以检测触屏事件并调用回调函数。CCTouchDelegate类的继承关系如下:
CCLayer、CCStandardTouchDelegate、CCTargetedTouchDelegate-->CCTouchDelegate。
CCTouchDelegate的子类中,CCStandardTouchDelegate协议是标准的获得多点触摸点的范例,CCTargetedTouchDelegate不用处理触摸点的集合,它是返回单点触摸。但是需要注意的是,CCTargetedTouchDelegate并没有屏幕多点触摸,而是将多点离散成单点,同时传递过来。可以在开始触摸的函数中返回true来实现之后获得的触摸点肯定是自己。此外,我们常用的类是布景层类CCLayer,也就是说,在布景层类中可以重写ccTouchesBegan等函数获得触屏的信息。下面就来详细介绍触屏事件。
1、触点类CCTouch:
一般把触摸点的信息放入触点类CCTouch中,主要的成员函数如下:
locationInView:获得点在画布中的位置。
previousLocationInView:之前在画布中的位置。
setTouchInfo:设置信息,三个参数:ID号、x坐标、y坐标。
getID:获得ID号。
CCTouch触点类封装了触摸点的信息,包括触摸点的横纵坐标值和触摸点的ID号,作为在函数中传递的参数,在回调函数中,通过一系列操作获得我们需要的坐标值,使用示例如下:
1 //通过locationInView获得坐标点
2 CCPoint point = touch->locationInView();
3 //通过坐标转换,转换为OpenGL坐标
4 point = CCDirector::sharedDirector()->convertToGL( point );
2、单点触摸函数:
ccTouchBegan:触摸开始,返回true可以使得该触摸点属于该函数的目标对象,该点的变化只会影响该目标对象函数调用,不会影响其他对象。
ccTouchMoved:触摸点移动。
ccTouchEnded:触摸动作结束。
ccTouchCancelled:系统中断通知需要取消触摸事件的时候会调用此函数,这个中断往往是因为应用长时间没有响应或者当前视图从系统的顶层上移除了。
注:CCTargetedTouchDelegate将触摸点分发给各个接收的函数,使用ccTouchBegan,并在返回时返回true,可以让这个触点属于这个函数的所属对象,并且其他对象不再接收该触点,这样之后再获得的触摸点肯定是它自己。这样就省去了你对多点触控时的判断。关于ccTouchCancelled,有很多人认为手指移出屏幕或者目标对象的范围就会触发ccTouchCancelled,但是这种情况下调用的依然是ccTouchEnded函数。事实上,系统中断通知需要取消触摸事件的时候会调用ccTouchCancelled,这个中断被调用往往是因为出现如下几种情况:
1、应用长时间没有响应或者当前视图从系统的顶层上移除。
2、程序进入后台时,有可能是来点中断、电量低中断和部分机型上的Home键被按下。
3、屏幕关闭和触摸的时候,某种原因导致距离传感器工作,比如:脸靠近。
4、部分触摸权限覆盖了本应用的触摸权限。
3、多点触摸函数:
ccTouchesBegan:触摸开始。
ccTouchesMoved:触摸点移动。
ccTouchesEnded:触摸动作结束。
ccTouchedCancelled:系统中断通知需要取消触摸事件的时候调用此函数。
下面对触摸事件进行使用示例说明,首先介绍布景层类和其子类使用触摸事件,代码如下:
1 //首先在初始化函数中加入setTouchEnabled
2 setTouchEnabled(true);
3
4 //重写registerWithTouchDispatcher函数,在此函数中通过导演类获得分发触摸类,并调用触摸代理addTargetedDelegate函数允许本布景层接受触摸事件。addTargetedDelegate函数的参数:加入代理的对象、触摸的优先级、是否“吞噬”所有的触摸点。
5 CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
注:触摸的优先级决定了触摸的分发顺序,触摸分发只和布景层的触摸优先级有关,和布景层的渲染顺序(zOrder)完全没有关系。哪怕是同样的触摸的优先级,也有可能底下一层先收到触摸,上面那层才接收到。所以处理不同层之间的触摸关系时,必须通过确定触摸优先级来实现这些层之间触摸点的处理顺序。优先级相同时数组里是乱序的,非插入顺序。CCStandardTouchDelegate标准触摸代理的触摸权限设置为最高的负无穷,也没有CCTargetedTouchDelegate目标触摸代理的最低的正无穷权限高。“吞噬”触摸点,如果在本布景层吞噬掉相应的触摸点,那么比它权限低的以及CCStandardTouchDelegate标准触摸代理无论是多高的权限全都收不到触摸分发。
如果非布景层和其子类想要使用触摸,那么继承相应代理即可。使用示例如下:
1 class Paddle: public CCSprite,public CCTargetedTouchDelegate
2 {
3 public:
4
5 //与布景层不同的是,这里需要在onEnter和onExit中注册、注销触摸的代理。方法和布景层相同。
6 virtual void onEnter();
7 virtual void onExit();
8 virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
9 virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
10 virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
11 }
多点触摸和单点触摸使用方法基本相同,只是把ccTouchBegan、ccTouchMoved、ccTouchEnded换成ccTouchesBegan、ccTouchesMoved、ccTouchesEnded。参数由原来的(CCTouch* touch, CCEvent* event)变成了(CCSet* touches, CCEvent* event)。在CCSet里可以获得多点的数量:touches->count(),也可以循环遍历获得多点触摸点CCSetIterator iter = touches->begin(); for(; iter != touches->end(); iter++)。