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

Cocos2d-x 3.x事件机制源码分析

2016-02-20 15:17 549 查看
整个事件机制,由以下几个部分构成:


事件 : 描述事件。

监听器 : 描述事件接收者与事件的“兴趣关系”。

分发器 : 针对所产生的事件,将事件分发给符合事件类型的事件接收者。

整个事件机制采用观察者模式,GL视图负责感应事件的产生,并包装事件,然后主动调用分发器的dispatchEvent函数用于分发。GL视图是观察者,图层或者说场景是被观察者。GL视图观察到事件,然后通过事件分发器通知被观察者。监听器,这么称呼有点名不副实,它并不是用于监听事件,而是作为一个桥梁为事件接收者(场景、图层、精灵等等)和事件分发者之间建立联系,当一个图层(或者精灵)关联到某一类型的监听器,则表明该图层(或精灵)对此类事件感兴趣,而监听器则是描述了图层(或精灵)与事件之间的这种“兴趣关系”,将监听器添加到分发器中,就是将这种“兴趣关系”告诉分发器,以便分发器能更好更合理的分发事件。


1、事件

事件,定义了事件的类型,如触摸、鼠标、键盘等等事件类型。每个事件类型都继承自Event。Event类封装了事件的一些共有属性。

class CC_DLL Event : public Ref
{
public:
//事件的类型主要有:触摸、键盘、加速计、鼠标、游戏手柄
enum class Type
{
TOUCH,
KEYBOARD,
ACCELERATION,
MOUSE,
FOCUS,
GAME_CONTROLLER,
CUSTOM
};

CC_CONSTRUCTOR_ACCESS:
Event(Type type);
public:

virtual ~Event();

inline Type getType() const { return _type; };

//停止事件的传播
inline void stopPropagation() { _isStopped = true; };

//检测当前事件是否停止了传播
inline bool isStopped() const { return _isStopped; };

//获得触发当前事件的对象
inline Node* getCurrentTarget() { return _currentTarget; };

protected:
inline void setCurrentTarget(Node* target) { _currentTarget = target; };

Type _type;     ///< Event type

bool _isStopped;       ///< whether the event has been stopped.
Node* _currentTarget;  ///< Current target

//EventDispatcher为友元类,EventDispatcher可以使用Event的方法
friend class EventDispatcher;
};


以下以触摸事件为例:

触摸事件

Touch类封装了所产生的触摸事件的信息,触摸事件通过_id来区别。EventTouch管理触摸事件,封装了触摸事件的属性。


class CC_DLL EventTouch : public Event
{
public:
static const int MAX_TOUCHES = 15;

/** EventCode Touch event code.*/
//触摸过程:开始、移动、末尾、不触摸
enum class EventCode
{
BEGAN,
MOVED,
ENDED,
CANCELLED
};

EventTouch();

inline EventCode getEventCode() const { return _eventCode; };

inline const std::vector<Touch*>& getTouches() const { return _touches; };
#if TOUCH_PERF_DEBUG

void setEventCode(EventCode eventCode) { _eventCode = eventCode; };

void setTouches(const std::vector<Touch*>& touches) { _touches = touches; };
#endif

private:
EventCode _eventCode;
//Touch类封装了 触摸事件的一些信息:触摸点、增量等等信息
std::vector<Touch*> _touches;
//GLView为友元类,GLView可以使用EventTouch的方法
friend class GLView;
};
class CC_DLL Touch : public Ref
{
public:
enum class DispatchMode {
ALL_AT_ONCE, /** All at once. */
ONE_BY_ONE,  /** One by one. */
};

Touch()
: _id(0),
_startPointCaptured(false)
{}

//获得当前触摸点的坐标
Vec2 getLocation() const;

//获得前一个触摸点的坐标
Vec2 getPreviousLocation() const;

//获得开始触摸时的坐标
Vec2 getStartLocation() const;

//获得前后两个触摸点之间增量
Vec2 getDelta() const;

Vec2 getLocationInView() const;

Vec2 getPreviousLocationInView() const;

Vec2 getStartLocationInView() const;

//设置触摸点信息
void setTouchInfo(int id, float x, float y)
{
_id = id;
_prevPoint = _point;
_point.x   = x;
_point.y   = y;
if (!_startPointCaptured)
{
_startPoint = _point;
_startPointCaptured = true;
_prevPoint = _point;
}
}

int getID() const
{
return _id;
}
private:
int _id;
bool _startPointCaptured;
Vec2 _startPoint;
Vec2 _point;
Vec2 _prevPoint;
};


2、事件监听器

由于事件分为多种,有触摸事件、鼠标事件等等。因此,cocos2d中也定义了多种事件监听器。但是所有的事件监听器都派生自EventListener。监听器负责为事件接收者 与 事件分发者 之间建立联系。


class CC_DLL EventListener : public Ref
{
public:
/** Type Event type.*/
enum class Type
{
UNKNOWN,
TOUCH_ONE_BY_ONE,
TOUCH_ALL_AT_ONCE,
KEYBOARD,
MOUSE,
ACCELERATION,
FOCUS,
GAME_CONTROLLER,
CUSTOM
};
typedef std::string ListenerID;
CC_CONSTRUCTOR_ACCESS:

EventListener();

bool init(Type t, const ListenerID& listenerID, const std::function<void(Event*)>& callback);
public:

virtual ~EventListener();

virtual bool checkAvailable() = 0;

virtual EventListener* clone() = 0;

//设置本监听器是否接受事件:true,接收;false,不接受
inline void setEnabled(bool enabled) { _isEnabled = enabled; };

inline bool isEnabled() const { return _isEnabled; };
protected:

inline void setPaused(bool paused) { _paused = paused; };
inline bool isPaused() const { return _paused; };
inline void setRegistered(bool registered) { _isRegistered = registered; };

//判断本监听器是否注册到分发器中
inline bool isRegistered() const { return _isRegistered; };

//获得当前事件类型
inline Type getType() const { return _type; };

inline const ListenerID& getListenerID() const { return _listenerID; };

inline void setFixedPriority(int fixedPriority) { _fixedPriority = fixedPriority; };

inline int getFixedPriority() const { return _fixedPriority; };

//获得被本监听器 所 监听的所有对象
inline Node* getAssociatedNode() const { return _node; };

std::function<void(Event*)> _onEvent;   /// Event callback function
Type _type;                             /// Event listener type
ListenerID _listenerID;                 /// Event listener ID
bool _isRegistered;                     /// Whether the listener has been added to dispatcher.
int   _fixedPriority;   // The higher the number, the higher the priority, 0 is for scene graph base priority.
Node* _node;            // scene graph based priority
bool _paused;           // Whether the listener is paused
bool _isEnabled;        // Whether the listener is enabled
friend class EventDispatcher;
};


触摸事件监听器

单点触摸事件监听器。


class CC_DLL EventListenerTouchOneByOne : public EventListener
{
public:
static const std::string LISTENER_ID;

/** Create a one by one touch event listener.
*/
static EventListenerTouchOneByOne* create();

/**
* Destructor.
* @js NA
*/
virtual ~EventListenerTouchOneByOne();

/** Whether or not to swall touches.
*
* @param needSwallow True if needs to swall touches.
*/
//设置是否向下传递触摸,若设置为true,则不向下传递触摸
void setSwallowTouches(bool needSwallow);
/** Is swall touches or not.
*
* @return True if needs to swall touches.
*/
bool isSwallowTouches();

/// Overrides
virtual EventListenerTouchOneByOne* clone() override;
virtual bool checkAvailable() override;
public:
typedef std::function<bool(Touch*, Event*)> ccTouchBeganCallback;
typedef std::function<void(Touch*, Event*)> ccTouchCallback;
ccTouchBeganCallback onTouchBegan;
ccTouchCallback onTouchMoved;
ccTouchCallback onTouchEnded;
ccTouchCallback onTouchCancelled;

CC_CONSTRUCTOR_ACCESS:
EventListenerTouchOneByOne();
bool init();

private:
std::vector<Touch*> _claimedTouches;
bool _needSwallow;

friend class EventDispatcher;
};


3、事件分发器

- 事件分发器维护了一个队列,这个队列是各种监听器的集合:

- 这个类管理事件监听器的订阅和事件的分发
- 事件监听器列表以这样的方式来进行管理:当事件正在分发的过程中,事件监听器可以被添加或者移除,包括事件监听器内部的监听器

以下这段代码


{
public:
// Adds event listener.

/** Adds a event listener for a specified event with the priority of scene graph.
*  @param listener The listener of a specified event.
*  @param node The priority of the listener is based on the draw order of this node.
*  @note  The priority of scene graph will be fixed value 0. So the order of listener item
*          in the vector will be ' <0, scene graph (0 priority), >0'.
*/
//为一个特定的事件添加一个事件监听器,该监听器的优先级是基于Node节点的绘图顺序。
void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);

//监听器的优先级由fixedPriority给出
void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);

EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);

// 移除 某个事件监听器
void removeEventListener(EventListener* listener);

//移除 特定类型的所有事件监听器
void removeEventListenersForType(EventListener::Type listenerType);
/** Removes all listeners which are associated with the specified target.
*
* @param target A given target node.
* @param recursive True if remove recursively, the default value is false.
*/
//移除 与target关联的所有事件监听器
void removeEventListenersForTarget(Node* target, bool recursive = false);

/** Removes all custom listeners with the same event name.
*
* @param customEventName A given event listener name which needs to be removed.
*/
void removeCustomEventListeners(const std::string& customEventName);
/** Removes all listeners.
*/
//移除所有的事件监听器
void removeAllEventListeners();
/////////////////////////////////////////////

// Pauses / Resumes event listener

/** Pauses all listeners which are associated the specified target.
*
* @param target A given target node.
* @param recursive True if pause recursively, the default value is false.
*/
void pauseEventListenersForTarget(Node* target, bool recursive = false);

/** Resumes all listeners which are associated the specified target.
*
* @param target A given target node.
* @param recursive True if resume recursively, the default value is false.
*/
void resumeEventListenersForTarget(Node* target, bool recursive = false);

/////////////////////////////////////////////

/** Sets listener's priority with fixed value.
*
* @param listener A given listener.
* @param fixedPriority The fixed priority value.
*/
void setPriority(EventListener* listener, int fixedPriority);
/** Whether to enable dispatching events.
*
* @param isEnabled  True if enable dispatching events.
*/
void setEnabled(bool isEnabled);
/** Checks whether dispatching events is enabled.
*
* @return True if dispatching events is enabled.
*/
bool isEnabled() const;
/////////////////////////////////////////////

/** Dispatches the event.
*  Also removes all EventListeners marked for deletion from the
*  event dispatcher list.
*
* @param event The event needs to be dispatched.
*/
//分发事件:主要接口(内部通过判别event的类型,来调用不同的分发函数)
void dispatchEvent(Event* event);
//...部分省略
/** Whether the dispatcher
isdispatching event */
int _inDispatch;

/** Whether to enable dispatching event */
bool _isEnabled;

int _nodePriorityIndex;

std::set<std::string> _internalCustomListenerIDs;
};


小结

GL视图负责感应事件,当有事件作用于GL视图的时候,GL视图将调用分发器EventDispatcher的接口(dispatchEvent)分发事件。而具体分发给谁,分发器将首先根据分发器中所维护的监听器队列来选择,因为可能有多个层希望接收这一类型事件,但是这些层的绘图顺序是不一样的,所以当选定了需要向哪些类型的监听器分发消息后,还将先把消息传递给最上层的图层(即本帧最后绘制的图层)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: