触屏事件是游戏的一个很重要的部分,没有了触屏,游戏就不叫游戏。而在Cocos2d-x中触屏事件是如何处理的呢?下面一起来学习学习。
一、首先,了解一下触摸相关的类:
1、CCTouch:封装触摸点,可以返回基于OpenGL或屏幕的点。
2、CCTouchDelegate:触摸事件委托,系统捕捉到事件后交由它或者它的子类处理,所以我们在处理触屏事件时需要继承此类。封装了下面这些函数:
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);
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);
CCLayer、CCTargetedTouchDelegate(单点触摸)、CCStandardTouchDelegate(多点触摸)都继承此类。
3、CCTouchDispatch:实现触摸事件的分发,封装下面两个函数:
void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority);
void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches);
可以把CCTargetedTouchDelegate和CCStandardTouchDelegate添加到分发列表中。
4、CCTouchHandler:封装了CCTouchDelegate和其对应的优先级,优先级越高,分发的时候就越容易获得事件的处理权。CCStandardTouchHandler和CCTargetedTouchHandler都继承于CCTouchHandler。
说那么多大家都会头晕,那就简单整理一下吧。CCTouch封装了触摸点,CCTouchDelegate是触摸事件委托,CCTouchHandler是封装CCTouchDelegate和其对应的优先级,而CCTouchDispatch是将触摸处理器分发到分发事件,根据优先级来调用。下面重点分析CCTouchDispatch。
/**
CCTouchDispatcher是个单例,程序刚启动时,导演类会将其设为EAGLView触摸代理,当玩家有触摸操作时,系统会自动调用它的对应方法。
CCLayer通过registerWithTouchDispatcher方法将自己注册到CCTouchDispatcher单例中,CCTouchDispatcher检测到触摸信息后,
会在注册队列中遍历这些对象,调用它们的响应方法,使它们可以响应触摸事件.
*/
class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate
{
public:
/**
* @lua NA
*/
~CCTouchDispatcher();
/**
* @lua NA
*/
bool init(void);
/**
* @lua NA
*/
CCTouchDispatcher()
: m_pTargetedHandlers(NULL)
, m_pStandardHandlers(NULL)
, m_pHandlersToAdd(NULL)
, m_pHandlersToRemove(NULL)
{}
public:
/** Whether or not the events are going to be dispatched. Default: true */
bool isDispatchEvents(void);
void setDispatchEvents(bool bDispatchEvents);
/** Adds a standard touch delegate to the dispatcher's list.
* See StandardTouchDelegate description.
* IMPORTANT: The delegate will be retained.
* @lua NA
*/
void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority);
/** Adds a targeted touch delegate to the dispatcher's list.
* See TargetedTouchDelegate description.
* IMPORTANT: The delegate will be retained.
* @lua NA
*/
void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches);
/** Removes a touch delegate.
* The delegate will be released
* @lua NA
*/
void removeDelegate(CCTouchDelegate *pDelegate);
/** Removes all touch delegates, releasing all the delegates
* @lua NA
*/
void removeAllDelegates(void);
/** Changes the priority of a previously added delegate. The lower the number,
* the higher the priority
* @lua NA
*/
void setPriority(int nPriority, CCTouchDelegate *pDelegate);
/**
* @lua NA
*/
void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);
/**
* @lua NA
*/
virtual void touchesBegan(CCSet* touches, CCEvent* pEvent);
/**
* @lua NA
*/
virtual void touchesMoved(CCSet* touches, CCEvent* pEvent);
/**
* @lua NA
*/
virtual void touchesEnded(CCSet* touches, CCEvent* pEvent);
/**
* @lua NA
*/
virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent);
public:
/**
* @lua NA
*/
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
protected:
void forceRemoveDelegate(CCTouchDelegate *pDelegate);
void forceAddHandler(CCTouchHandler *pHandler, CCArray* pArray);
void forceRemoveAllDelegates(void);
void rearrangeHandlers(CCArray* pArray);
CCTouchHandler* findHandler(CCArray* pArray, CCTouchDelegate *pDelegate);
protected:
// 目标注册队列,作用和m_pStandardHandlers大体相同,唯一区别就是m_pTargetedHandlers可以吞噬自身响应的事件,以阻止
// 信息继续向下传递,而m_pStandardHandlers没有此功能。CCMenu就是向该队列注册的。
CCArray* m_pTargetedHandlers;
// 标准注册队列,当CCLayer对象调用registerWithTouchDispatcher方法时,会将其添加到该数组中,所有该数组中的对象在
// 玩家触摸屏幕时都会被调用自身的相关方法:ccTouchesBegan、ccTouchesMoved、ccTouchEnded
CCArray* m_pStandardHandlers;
// 是否被锁定,当玩家做了触摸操作,CCTouchDispatcher开始遍历注册队列时,该变量会被设置为YES,此时是不能向队列中
// 添加新的对象,或者从队列中删除对象的。只有当遍历结束,m_bLocked被置回NO后才可以添加或者删除。如果在锁定过程中
// 执行了这两种操作,那么操作对象会被放入对应的临时队列中,解锁后再把它们同步到注册队列中。
bool m_bLocked;
// 是否有等待添加的对象,当CCTouchDispatcher被锁定时,如果有新的对象要注册进来则会被添加进一个临时队列,该队列的
// 所有成员都是待注册对象,如果队列不为空,m_bToAdd就会被设为YES,那么当锁定解除后,就会把该队列所有成员全部移入
// standardHandlers或targetedHandlers(它会根据对象的类型自行区分),操作完成后清空临时队列,m_bToAdd设为NO
bool m_bToAdd;
// 是否有等待删除的对象,同添加一样,在CCTouchDispatcher被锁定时,需要删除的对象会被放入另一个临时队列,该队列的成员都是等待注销的,
// 如果队列不为空,m_bToRemove就会被值为YES,锁定解除后再将队列成员依此从注册队列中删除(具体哪个队列会自动判断),
// 操作完成后清空临时队列,m_bToRemove置回NO。
bool m_bToRemove;
// 存放等待注册对象的队列
CCArray* m_pHandlersToAdd;
// 存放等待注销对象的队列
struct _ccCArray *m_pHandlersToRemove;
// 是否要清空注册队列,同m_bToRemove一样,清空队列同样需要等到解锁后才能执行,这个变量就是标记是否需要清空的。
bool m_bToQuit;
// 有触摸操作时,是否遍历注册队列,默认一直是YES
bool m_bDispatchEvents;
// 4, 1 for each type of event
// 一个长度为ccTouchMax=4的结构体队列,每个成员都是一个ccTouchHandlerHelperData结构体,用来存储CCTOUCHBEGAN,CCTOUCHMOVED,
// CCTOUCHENDED和CCTOUCHCANCELLED四中触摸事件的调用方法。
struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];
};
// end of input group
/// @}
NS_CC_END
#endif // __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__
static int less(const CCObject* p1, const CCObject* p2)
{
return ((CCTouchHandler*)p1)->getPriority() < ((CCTouchHandler*)p2)->getPriority();
}
bool CCTouchDispatcher::isDispatchEvents(void)
{
return m_bDispatchEvents;
}
void CCTouchDispatcher::setDispatchEvents(bool bDispatchEvents)
{
m_bDispatchEvents = bDispatchEvents;
}
/*
+(id) allocWithZone:(CCZone *)zone
{
@synchronized(self) {
CCAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton.");
return [super allocWithZone:zone];
}
return nil; // on subs