整个事件机制,由以下几个部分构成:
事件 : 描述事件。
监听器 : 描述事件接收者与事件的“兴趣关系”。
分发器 : 针对所产生的事件,将事件分发给符合事件类型的事件接收者。
整个事件机制采用观察者模式,GL视图负责感应事件的产生,并包装事件,然后主动调用分发器的dispatchEvent函数用于分发。GL视图是观察者,图层或者说场景是被观察者。GL视图观察到事件,然后通过事件分发器通知被观察者。监听器,这么称呼有点名不副实,它并不是用于监听事件,而是作为一个桥梁为事件接收者(场景、图层、精灵等等)和事件分发者之间建立联系,当一个图层(或者精灵)关联到某一类型的监听器,则表明该图层(或精灵)对此类事件感兴趣,而监听器则是描述了图层(或精灵)与事件之间的这种“兴趣关系”,将监听器添加到分发器中,就是将这种“兴趣关系”告诉分发器,以便分发器能更好更合理的分发事件。
事件,定义了事件的类型,如触摸、鼠标、键盘等等事件类型。每个事件类型都继承自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;
};
由于事件分为多种,有触摸事件、鼠标事件等等。因此,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;
};
- 事件分发器维护了一个队列,这个队列是各种监听器的集合:
- 这个类管理事件监听器的订阅和事件的分发
- 事件监听器列表以这样的方式来进行管理:当事件正在分发的过程中,事件监听器可以被添加或者移除,包括事件监听器内部的监听器
以下这段代码
{
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)分发事件。而具体分发给谁,分发器将首先根据分发器中所维护的监听器队列来选择,因为可能有多个层希望接收这一类型事件,但是这些层的绘图顺序是不一样的,所以当选定了需要向哪些类型的监听器分发消息后,还将先把消息传递给最上层的图层(即本帧最后绘制的图层)。