cocos2d-x一般把触摸点的信息封装成触点类CCTouch中 引擎专门提供了一个负责分发用户操作的信息类 CCTouchDispatcher 作用就是响应对象分发CCTouch对象
CCTouchDispatcher主要派生的有三个类 CCLayer CCTargetedTouchDelegate CCStandardTouchDelegate
CCTouchDispatcher主要成员函数:
addTargetedDelegate(CCTargetedTouchDelegate* pDelegate, int nPriority,bool bSwallowsTouches);//主要是将CCTouchDispatcher的对象添加到分发器中
addStandardDelegates(CCTargetedTouchDelegate* pDelegate, int nPriority);
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) //触摸事件的回调函数
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)
Summary:实际开发中 需要我们触摸的 一种是布景层 一种是非布景层
第一种是布景层的很简单 cocos2d-x已经帮我们封装好了一些功能 就是在初始化函数中setTouchEnabled 然后重写registerWithTouchDispatcher ccTouchBegan ccTouchMoved ccTouchEnded ccTouchCancelled函数 其中在registerWithTouchDispatcher函数中通过导演类过的触发类 并调用addTargetedDelegate或者addStandardDelegates函数
第二种不是布景层 其实不仅仅只是布景层具有触摸事件机制 每一个CCNode对象都可以 只是cocos2d-x把层现成提供了这样的功能 在这里你需要触发的对象不再是一个层而是一张纹理或者其他对象 就像菜单按钮一样 非布景层想要使用触摸 只要继承相关代理即可
class Paddle : public CCSprite, public CCTargetedTouchDelegate
{
public:
Paddle(void);
virtual ~Paddle(void);
CCRect rect();
bool initWithTexture(CCTexture2D* aTexture);
virtual void onEnter();//初始化函数 利用导演类注册代理函数
virtual void onExit();//这里不像CCLayer 我们需要手动注销代理函数
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);
virtual CCObject* copyWithZone(CCZone *pZone);
virtual void touchDelegateRetain();
virtual void touchDelegateRelease();
}
void Paddle::onEnter()
{
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
CCSprite::onEnter();
}
void Paddle::onExit()
{
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->removeDelegate(this);
CCSprite::onExit();
}
Summary:在实际开发中 一种方式 我们直接创建一个层 实现接口 注册 然后重载回调函数 在重载回调函数 然后判断触摸点的CCPoint和纹理->getpostion得到的CCPoint相互比较从而得到用户现在触摸点是否在纹理的区域内 实际上cocos2d-x的底层也是这么判断的 相信很多windows程序员对这一点很熟悉 但是这种方法似乎只适合一个场景中只有一个需要判断的纹理你(比如前微信飞机大战中 只需要触摸自己的飞机就OK) 如果太多 每一次触摸你既要遍历得到每一个纹理的位置 然后判断 得到不同的响应 显得很繁琐而且最大的缺点 就是判断的方法并不是很精准 因为两个位置的比较 毕竟是我们认为去判断的 比如一个圆形的纹理图片 但是我们只能按照矩形区域来判断 如果不是自己计算很精准 会带来很大的误差
所以我们需要第二种方法 让程序员从繁琐的CCPoint计算中解脱出来 就是需要响应触摸事件纹理继承相关代理 就如同上述代码所示 这样计算的任务就交给cocos2d-x类完成 我们只需要完成一些回调函数的逻辑即可 一方面精准了 另一方面可以很简洁
cocos2d-x两种触摸事件:
1,带目标的触摸事件CCTargetedTouchDelegate:实际上就是单点触摸事件
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) //触摸开始 返回true可以使得触摸点属于该函数的目标对象 该点的变化只会影响该目标函数的调用 不会影响其他对象
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) 处理Touch Move 事件
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) 处理用户放开事件
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) 处理Touch被打断事件.
为了使一个对象接受带目标的触摸事件 主要有一下四个步骤:
1,对象需要实现CCTargetedTouchDelegate提供的接口
2,使用addTargetedDelegate把自己注册给触摸事件分发器 这里需要注意的是 这里的最后一个参数是一个bool类型的变量 当设置为true的时候会产生吞噬效果 就是所有优先级比自己低的接受对象都无法接受到触摸事件
3,重载事件回调函数 处理触摸事件 这里需要注意的是 在触摸开始事件的函数里 返回值true以捕捉事件
4,当不再需要接受触摸事件的时候,使用removeDelegate方法来注销触摸事件接受
2,标准触摸事件CCStandardTouchDelegate:实际上就是多点触摸事件
CCStandardTouchDelegate包含四个回调函数,分别如下:
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) 处理用户按下事件
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) 处理Touch Move 事件
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) 处理用户放开事件
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) 处理Touch被打断事件,如来电话了。
为了使一个对象接受标准触摸事件 主要有一下四个步骤:
1,对象需要实现CCStandardTouchDelegate提供的接口
2,使用addStandardDelegate把自己注册给触摸事件分发器
3,重载事件回调函数 处理触摸事件
4,当不再需要接受触摸事件的时候,使用removeDelegate方法来注销触摸事件接受
Summary:研究过cocos2d-x的源代码之后 发现他们的做法是 首先创建一个主游戏的场景 然后创建需要显示在这个场景中各种层 其中需要实现触摸事件的层注册之后 在运行这个场景中 当有触摸事件发生的时候 就会触发每一个层中的回调函数 但是一般的做法层只是负责接收触摸事件 并把触摸事件分发给代理 然后由代理来完成触摸事件
使用代理设计模式 可以解除触摸层和实际处理事件的精灵层的耦合 这样的好处是 能有效的分离触摸手势的识别和处理事件两个部分 使代码结构清晰