您的位置:首页 > 移动开发 > Cocos引擎

Cocos2d-x之CCTouchDispatcher事件分发

2013-03-28 11:43 387 查看
使用过CCLayer的都应该知道,CCLayer的众多父类中有CCTouchDelegate这么一个类,他使CCLayer能接收touch事件成为可能。cocos2d-x的touch事件是由CCTouchDispatcher这个touch分发器类来进行派发的,所有需要接收touch事件的对象都必须注册到CCTouchDispatcher中,而只有继承于CCTouchDelegate的对象才能被注册到touch分发器中。
先看看cocos2d-x的touch事件的触发流程,我们能看得见的游戏界面我且称之为视图(view),touch的产生正是从视图开始的,在程序的消息处理中心检测到touch事件时,将事件整理成CCTouch的集合并传递给注册在视图内的touch分发器CCTouchDispatcher,这个touch分发器是在导演类设置
openglView的时候注册的:

//1、直接设置touch分发器
void CCDirector::setTouchDispatcher(CCTouchDispatcher* pTouchDispatcher)
{
//设置touch分发器
if (m_pTouchDispatcher != pTouchDispatcher)
{
CC_SAFE_RETAIN(pTouchDispatcher);
CC_SAFE_RELEASE(m_pTouchDispatcher);
m_pTouchDispatcher = pTouchDispatcher;
}
}

//2、导演类初始化的时候创建touch分发器
bool CCDirector::init(void)
{
......
//导演类初始化的时候生成touch分发器
m_pTouchDispatcher = new CCTouchDispatcher();
m_pTouchDispatcher->init();

... ...

return true;
}

void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView)
{
CCAssert(pobOpenGLView, "opengl view should not be null");

if (m_pobOpenGLView != pobOpenGLView)
{
......
//注册touch分发器到openglView中,接收view传递过来的touch事件

m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);
m_pTouchDispatcher->setDispatchEvents(true);
}
}

在查看touch分发器怎么处理touch事件之前,先了解传递的数据CCTouch,CCtouch的数据很简单,只有属性:

int m_nId;
CCPoint m_point;
CCPoint m_prevPoint;
CCTouch.cpp:

// returns the current touch location in screen coordinates
CCPoint CCTouch::getLocationInView() const
{
//获取屏幕坐标
return m_point;
}

// returns the current previous location in screen coordinates
CCPoint CCTouch::getPreviousLocationInView() const
{
//获取上一次的屏幕坐标
return m_prevPoint;
}

// returns the current touch location in OpenGL coordinates
CCPoint CCTouch::getLocation() const
{
//获取在opengl坐标系中的坐标
return CCDirector::sharedDirector()->convertToGL(m_point);
}

// returns the previous touch location in OpenGL coordinates
CCPoint CCTouch::getPreviousLocation() const
{
//获取上一次在opengl坐标系中的位置
return CCDirector::sharedDirector()->convertToGL(m_prevPoint);
}

// returns the delta position between the current location and the previous location in OpenGL coordinates
CCPoint CCTouch::getDelta() const
{
//返回当前和上次位置在opengl坐标系中差值
return ccpSub(getLocation(), getPreviousLocation());
}
CCTouch提供查询坐标点的接口。

所有能接收touch事件的对象都需要继承于CCTouchDelegate,这个类定义了接收touch事件的众多接口,CCTouchDelegateProtocol.h:

class CC_DLL CCTouchDelegate
{
public:

CCTouchDelegate() {}

virtual ~CCTouchDelegate()
{
}

virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); return false;};
// optional

virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}

// optional
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}

};

//此类型的触控对象,可以通过ccTouchBegan的返回值决定此次touch是否有后续的反馈
//返回值为false的时候,此次touch后续的moved、ended、cancelled都不再反馈给此触控对象
//具备touch阻断功能的触控对象
class CC_DLL CCTargetedTouchDelegate : public CCTouchDelegate
{
public:
/** Return YES to claim the touch.
@since v0
*/
virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);return false;};

// optional
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
};

//此类型的触控对象不具有阻止后续反馈的功能,一次touch事件,触控对象将接收到所有的后续反馈
//典型的触控对象接收多点触控数据
class CC_DLL CCStandardTouchDelegate : public CCTouchDelegate
{
public:
// optional
virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
};

其中定义了两种触控对象,一种是接收单触控并具有阻挡策略,另一种是接收多点触控

touch分发器中,将触控对象转换为触控对象句柄CCTouchHandler之后,才进行存储和处理的,CCTouchHandler.h:

//触控对象的句柄,相当于一个容器,保存了触控对象以及触控对象的触控优先级
class CC_DLL  CCTouchHandler : public CCObject
{
public:
virtual ~CCTouchHandler(void);

/** delegate */
//触控对象的获取与设置
CCTouchDelegate* getDelegate();
void setDelegate(CCTouchDelegate *pDelegate);

/** priority */
//触控优先级的获取与设置
int getPriority(void);
void setPriority(int nPriority);

/** enabled selectors */
//好像没有什么用处
int getEnabledSelectors(void);
void setEnalbedSelectors(int nValue);

/** initializes a TouchHandler with a delegate and a priority */
//初始化触控句柄,参数为触控对象和触控优先级
virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);

public:
/** allocates a TouchHandler with a delegate and a priority */
//创建一个触控句柄,参数为触控对象和触控优先级
static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);

protected:
CCTouchDelegate *m_pDelegate;
int m_nPriority;
int m_nEnabledSelectors;
};

/** CCStandardTouchHandler
It forwards each event to the delegate.
*/

//典型触控句柄
class CC_DLL  CCStandardTouchHandler : public CCTouchHandler
{
public:
/** initializes a TouchHandler with a delegate and a priority */
virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);

public:
/** allocates a TouchHandler with a delegate and a priority */
static CCStandardTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
};

/**
CCTargetedTouchHandler
Object than contains the claimed touches and if it swallows touches.
Used internally by TouchDispatcher
*/
//具有touch阻断功能的触控句柄
class CC_DLL  CCTargetedTouchHandler : public CCTouchHandler
{
public:
~CCTargetedTouchHandler(void);

/** whether or not the touches are swallowed */
//是否阻止touch事件冒泡,继续分发给接下来的其他对象
bool isSwallowsTouches(void);
void setSwallowsTouches(bool bSwallowsTouches);

/** MutableSet that contains the claimed touches */
//获取集合、此集合中保存了touch对象,针对这些touch对象,触控对象将接收他们的后续反馈
CCSet* getClaimedTouches(void);

/** initializes a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow);

public:
/** allocates a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
static CCTargetedTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow);

protected:
bool m_bSwallowsTouches;
CCSet *m_pClaimedTouches;
};
触控对象句柄也有两种,单点触控对象句柄具有一个集合属性 CCSet *m_pClaimedTouches,用来存储得到认可的touch事件,使该事件的后续反馈将对这个触控对象有效。

接下来看看touch分发器的具体实现,看看他是怎么样分发touch消息的,主要分发逻辑在touches方法中。

CCTouchDispatcher.h:

#ifndef __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__
#define __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__

#include "CCTouchDelegateProtocol.h"
#include "cocoa/CCObject.h"
#include "cocoa/CCArray.h"

NS_CC_BEGIN

/**
* @addtogroup input
* @{
*/

typedef enum
{
ccTouchSelectorBeganBit = 1 << 0,
ccTouchSelectorMovedBit = 1 << 1,
ccTouchSelectorEndedBit = 1 << 2,
ccTouchSelectorCancelledBit = 1 << 3,
ccTouchSelectorAllBits = ( ccTouchSelectorBeganBit | ccTouchSelectorMovedBit | ccTouchSelectorEndedBit | ccTouchSelectorCancelledBit),
} ccTouchSelectorFlag;

enum {
CCTOUCHBEGAN,
CCTOUCHMOVED,
CCTOUCHENDED,
CCTOUCHCANCELLED,

ccTouchMax,
};

class CCSet;
class CCEvent;

struct ccTouchHandlerHelperData {
// we only use the type
//    void (StandardTouchDelegate::*touchesSel)(CCSet*, CCEvent*);
//    void (TargetedTouchDelegate::*touchSel)(NSTouch*, CCEvent*);
int  m_type;
};

class CC_DLL EGLTouchDelegate
{
public:
virtual void touchesBegan(CCSet* touches, CCEvent* pEvent) = 0;
virtual void touchesMoved(CCSet* touches, CCEvent* pEvent) = 0;
virtual void touchesEnded(CCSet* touches, CCEvent* pEvent) = 0;
virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent) = 0;

virtual ~EGLTouchDelegate() {}
};

class CCTouchHandler;
struct _ccCArray;

class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate
{
public:
~CCTouchDispatcher();
bool init(void);
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 */
//是否分发touch事件
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.
*/
//添加接收touch事件的典型触控对象
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.
*/
//添加接受touch事件的,具有阻断功能的触控对象
void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches);

/** Removes a touch delegate.
The delegate will be released
*/
//移除触控对象
void removeDelegate(CCTouchDelegate *pDelegate);

/** Removes all touch delegates, releasing all the delegates */
void removeAllDelegates(void);

/** Changes the priority of a previously added delegate. The lower the number,
the higher the priority */
void setPriority(int nPriority, CCTouchDelegate *pDelegate);

void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);

virtual void touchesBegan(CCSet* touches, CCEvent* pEvent);
virtual void touchesMoved(CCSet* touches, CCEvent* pEvent);
virtual void touchesEnded(CCSet* touches, CCEvent* pEvent);
virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent);

public:
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:

//两个队列,用来保存注册进来的单触控对象和多点触控对象
CCArray* m_pTargetedHandlers;
CCArray* m_pStandardHandlers;

//触控对象队列是否被锁定不可增删改
bool m_bLocked;

//是否有触控对象在等待添加到触控队列中
bool m_bToAdd;

//是否有触控对象在等待从触控队列中移除掉
bool m_bToRemove;

//保存等待加入触控队列的触控对象
CCArray* m_pHandlersToAdd;

//保存等待从触控队列中删除的触控对象
struct _ccCArray *m_pHandlersToRemove;

//是否将推出
bool m_bToQuit;

//是否分发touch事件
bool m_bDispatchEvents;

// 4, 1 for each type of event
struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];
};

// end of input group
/// @}

NS_CC_END

#endif // __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: