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)分发事件。而具体分发给谁,分发器将首先根据分发器中所维护的监听器队列来选择,因为可能有多个层希望接收这一类型事件,但是这些层的绘图顺序是不一样的,所以当选定了需要向哪些类型的监听器分发消息后,还将先把消息传递给最上层的图层(即本帧最后绘制的图层)。相关文章推荐
- cocos2d-x新手学习之Helloworld(第三篇)[版本号:cocos2d-x-3.1.1]
- Cocos2d-x 3.x启动过程
- Cocos2d-x 3.x开篇
- Cocos2d-x lua游戏开发之安装Lua到mac系统
- 基于cocos2d-x的含有物理属性的物件创建模板(优化版)
- cocos2d-js关于对话框Layer的屏幕适配
- 2、创建第一个cocos2d-x项目
- quick-cocos2dx学习笔记(一)引擎结构总览和创建项目
- cocos2dx ——浅析cocos2dx3.2引擎目录
- Cocos2dx一步一步实现Android端热更新(C++)
- 第一章cocos2d-x
- quickcocos2dx scheduler妙用
- cocos2dx C++ 绑定到 Lua时两个问题
- cocos ide 调试lua 程序自动关闭问题的解决
- 使用BabeLua在cocos2d-x中调试Lua
- cocos2d-x 3.9 android studio项目命令行打包
- Cocos2d-x LayoutComponent的使用
- Cocos2d-x Layout使用三
- Cocos2d-x Layout的使用二
- Cocos2d-x Layout使用