Cocos2d-x学习(三):触屏事件(单点触屏)

cocos2d-x中的触屏事件分为多点触屏和单点触屏,而多点触屏用到的地方并不是很多,所以先主要记录一下单点触屏的用法和基本原理。


一般经常用到的触屏的情况有两种:一种是Layer统一接收触屏消息,然后由程序根据需要分发给不同位置的精灵;另一种情况是自定义一个可以接收触屏消息的Sprite,比如类似于Button功能的Sprite,这就需要在定义Sprite的时候就要定义好触屏所触发的操作!


下面就两种情况分别记录一下基本用法:

1.Layer接收触屏消息

用法很简单,只需要覆写父类的4个方法(可以根据需要,但是ccTouchBegan()是必须要覆写的,并且其返回值对触屏事件的传递有影响,后面会总结),并在init()方法中将其添加到CCTouchDispacher中,代码如下

[cpp]  view plain copy
  1. <span style="font-size:12px;">class TouchableLayer: public CCLayer   
  2. {  
  3. public:  
  4.       
  5.     virtual bool init();  
  6.       
  7.     LAYER_NODE_FUNC(TouchableLayer);  
  8.       
  9.     virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);</span>  
[cpp]  view plain copy
  1. <span style="font-size:12px;">  
  2.     virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);  
  3.     virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);  
  4.     virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);  
  5. };</span>  
在Layer的init()中添加如下代码,这个Layer就可以接收到触屏消息了

[cpp]  view plain copy
  1. <span style="font-size:12px;">CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true);</span>  

如果想通过这种方式判断具体触摸的Sprite或者区域等信息,就需要自己写判断和分发消息的代码了!

2.自定义可以接收触屏消息的Sprite

这种稍微复杂一些,但是还是比较好理解的,首先要先继承CCSprite或者其父类,以满足精灵形状,位置等信息的要求,另外还需要继承触屏事件委托CCTargetedTouchDelegate,CCTargetedTouchDelegate中定义了接收触屏信息的回调虚函数,而这些虚函数,正是我们需要覆写的部分,代码如下

[cpp]  view plain copy
  1. <span style="font-size:12px;">class TouchableSprite: public CCSprite, public CCTargetedTouchDelegate  
  2. {  
  3.       
  4. public:  
  5.     TouchableSprite();  
  6.     virtual ~TouchableSprite();  
  7.       
  8.     static TouchableSprite *touchSpriteWithFile(const char *file);  
  9.       
  10.     bool initWithFile(const char *file);  
  11.       
  12.     virtual void onEnter();  
  13.     virtual void onExit();  
  14.       
  15.     CCRect rect();  
  16.     bool containsTouchLocation(CCTouch *touch);  
  17.       
  18.     virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);  
  19.     virtual void ccTouchMoved(CCTouch *touch, CCEvent *event);  
  20.     virtual void ccTouchEnded(CCTouch *touch, CCEvent *event);  
  21.   
  22. };  
  23. </span>  
重点在于判断自定义Sprite是否被点击,这时就需要得到精灵所在的矩形了,这时又有两种判断方式

(1)得到触屏所在位置,然后根据精灵所在位置的矩形区域和触屏的点判断是否包含,如果包含,则说明触摸到了Sprite。这里写了一个得到精灵当前所在矩形的方法

[cpp]  view plain copy
  1. <span style="font-size:12px;">CCRect TouchableSprite::rect()  
  2. {  
  3.     CCSize size = getContentSize();  
  4.     CCPoint pos = getPosition();  
  5.   
  6.     return CCRectMake(pos.x - size.width / 2, pos.y - size.height / 2, size.width, size.height);  
  7. }</span>  
然后在每次点击的时候都需要将当前触屏位置转换为GL坐标的位置,然后和Sprite所在矩形做包含判断

[cpp]  view plain copy
  1. <span style="font-size:12px;">bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch)  
  2. {  
  3.     CCPoint touchPoint = touch->locationInView(touch->view());  
  4.     touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);  
  5.       
  6.     return CCRect::CCRectContainsPoint(rect(), touchPoint);  
  7. }</span>  

(2)其实cocos2d为我们提供了一种相对简单的方法,但是原理类似,调用CCNode中定义的convertTouchToNodeSpaceAR()方法,将触屏点转化为相对于结点的相对坐标

(ps:由于默认anchor点是中点,所以每一个Sprite上的相对坐标系是从(-width / 2, -height / 2)为左上角点坐标),所以上面的两个方法需要修改一下

[cpp]  view plain copy
  1. <span style="font-size:12px;">CCRect TouchableSprite::rect()  
  2. {  
  3.     CCSize size = getTexture()->getContentSize();  
  4.   
  5.     return CCRectMake(-size.width / 2, -size.height / 2, size.width, size.height);  
  6. }</span>  
[cpp]  view plain copy
  1. <span style="font-size:12px;">bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch)  
  2. {  
  3.     return CCRect::CCRectContainsPoint(rect(), convertTouchToNodeSpaceAR(touch));  
  4. }</span>  

3.触屏传递顺序

另外需要主要的是

[cpp]  view plain copy
  1. <span style="font-size:12px;">virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);</span>  
方法,其返回值是对此触屏消息有影响的,简单来说,如果返回false,表示不处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,而交由后续接收触屏消息的对象处理;如果返回true,表示会处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,并且消耗掉此触屏消息。

总结如下:

1.CCLayer 只有一层的情况:

virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
a.返回false,则ccTouchMoved(),ccTouchEnded()不会再接收到消息
b.返回true,则ccTouchMoved(),ccTouchEnded()可以接收到消息

2.CCLayer 有多层的情况:
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
a.返回false,则本层的ccTouchMoved(),ccTouchEnded()不会再接收到消息,但是本层之下的其它层会接收到消息
b.返回true,则本层的ccTouchMoved(),ccTouchEnded()可以接收到消息,但是本层之下的其它层不能再接收到消息

3.有自定义接收触摸消息的精灵的情况:
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
a.返回false,则此精灵的ccTouchMoved(),ccTouchEnded()不会再接收到消息,而此精灵所在的层会接收到触摸消息(如果精灵所在层没有设置接收触摸消息,则向下传递
b.返回true,则此精灵的ccTouchMoved(),ccTouchEnded()会继续接收消息,并消耗此消息(即不再向所在层和其他层传递)

测试代码

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值