cocos2d-x自定义可点击/可处理事件/可接受触屏消息的Sprite

本篇大部分摘自http://blog.csdn.net/onerain88/article/details/7550009(写的好清楚)

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

1.Layer接收触屏消息(请参考原文)

总结下就是:在layer中的sprite,他们可能会处于同一层,那么,最重要的就是怎么把事件传递给希望处理事件的sprite。方法就是通过优先级去“接收事件”,如果不处理,ccTouchBegin的返回值就设置为false,如果处理,就设置为true,表示拦截此消息。这样,事件就不会往更低优先级的sprite传递了。

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

我比较感兴趣的是自定义Sprite。

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

class TouchableSprite: public CCSprite, public CCTargetedTouchDelegate  
{  
      
public:  
    TouchableSprite();  
    virtual ~TouchableSprite();  
      
    static TouchableSprite *touchSpriteWithFile(const char *file);  
      
    bool initWithFile(const char *file);  
      
    virtual void onEnter();  
    virtual void onExit();  
      
    CCRect rect();  
    bool containsTouchLocation(CCTouch *touch);  
      
    virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);  
    virtual void ccTouchMoved(CCTouch *touch, CCEvent *event);  
    virtual void ccTouchEnded(CCTouch *touch, CCEvent *event);  
  
};  

重点在于判断自定义Sprite是否被点击,这时就需要得到精灵所在的矩形了,这时又有两种判断方式

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

CCRect TouchableSprite::rect()  
{  
    CCSize size = getContentSize();  
    CCPoint pos = getPosition();  
  
    return CCRectMake(pos.x - size.width / 2, pos.y - size.height / 2, size.width, size.height);  }
然后在每次点击的时候都需要将当前触屏位置转换为GL坐标的位置,然后和Sprite所在矩形做包含判断

bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch)  
{  
    CCPoint touchPoint = touch->locationInView(touch->view());         //这里由于版本更新,改为touch->getLoactionInView()
    touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);  
      
    return CCRect::CCRectContainsPoint(rect(), touchPoint);  
}
转载作者补充:

可以使用getLocation()取代上面那两句代码,cocos2d-x相关源码如下:

// returns the current touch location in screen coordinates
CCPoint CCTouch::getLocationInView() const 
{ 
    return m_point; 
}
// returns the current touch location in OpenGL coordinates
CCPoint CCTouch::getLocation() const
{ 
    return CCDirector::sharedDirector()->convertToGL(m_point); 
}
这里要提下坐标系统,getLocationInView获取的是屏幕坐标,不同设备坐标系统不同,例如ios是左上角为原点。而cocos2d-x是左下角为原点。所以在cocos2d-x中做运算时候,要转为GL坐标系,即cocos2d-x默认的“可视屏幕的坐标系统”。

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

CCRect TouchableSprite::rect()  
{  
    CCSize size = getTexture()->getContentSize();  
  
    return CCRectMake(-size.width / 2, -size.height / 2, size.width, size.height);  
}
bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch)  
{  
    return CCRect::CCRectContainsPoint(rect(), convertTouchToNodeSpaceAR(touch));  
}

关于事件处理还可以参考本文

http://blog.linguofeng.com/archive/2012/09/12/cocos2d-x-touch.html

可以借鉴该文点击事件处理方法

void MyLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {
    // 单点
    CCTouch *pTouch = (CCTouch*)(pTouches->anyObject());

    // 所有点
    for(CCSetIterator iterTouch = pTouches->begin(); iterTouch != pTouches->end(); iterTouch++) {
        CCTouch *pCurTouch =  (CCTouch*)(*iterTouch);
    }

    // 获取点在视图中的坐标(左上角为原点)
    CCPoint touchLocation = pTouch->getLocationInView();
    // 把点的坐标转换成OpenGL坐标(左下角为原点)
    touchLocation = CCDirector::sharedDirector()->convertToGL(touchLocation);
    // 把OpenGL的坐标转换成CCLayer的坐标
    CCPoint local = convertToNodeSpace(touchLocation)
    // 大小为100x100,坐标为(0, 0)的矩形
    CCRect * rect = CCRectMake(0, 0, 100, 100);
    // 判断该坐标是否在rect矩形内
    bool flag = rect.containsPoint(local)
    if(flag) {
        // 回调
    } else {
        // 不执行
    }
}

其它处理方法,可以借鉴CCTableView

http://blog.csdn.net/xzongyuan/article/details/9177421

触屏传递顺序

另外需要主要的是

virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);

方法,其返回值是对此触屏消息有影响的,简单来说,如果返回false,表示不处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,而交由后续接收触屏消息的对象处理;如果返回true,表示会处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,并且消耗掉此触屏消息。


最后,要在进入时候添加触屏接口

void TouchableSprite::onEnter(){
	CCSprite::onEnter();
	CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,true);
}

void TouchableSprite::onExit(){
	CCSprite::onExit();
	CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值