对应源码位置:(1)cocos2d-x-3.3\cocos\base\CCEvent*
先从 Event 类开头
class CC_DLL Event : public Ref
{
public:
//可想而知 对应这几个类型 分别有对应的Event子类
//以及 对应事件的 eventlistener
enum class Type
{
TOUCH,
KEYBOARD,
ACCELERATION,
MOUSE,
FOCUS,
GAME_CONTROLLER,
CUSTOM
};
/** Constructor */
Event(Type type);
public:
/** Destructor */
virtual ~Event();
/** Gets the event type */
inline Type getType() const { return _type; };
/** Stops propagation for current event */
inline void stopPropagation() { _isStopped = true; };
/** Checks whether the event has been stopped */
inline bool isStopped() const { return _isStopped; };
inline Node* getCurrentTarget() { return _currentTarget; };
protected:
/** Sets current target */
inline void setCurrentTarget(Node* target) { _currentTarget = target; };
//事件类型
Type _type; ///< Event type
//是否阻止传播 也就是所谓的 swallow 是否吞下这个事件
bool _isStopped; ///< whether the event has been stopped.
Node* _currentTarget; ///< Current target
friend class EventDispatcher;
};
再来看看 EventCustom 这个子类,也就是所谓自定义事件
class CC_DLL EventCustom : public Event
{
public:
/** Constructor */
EventCustom(const std::string& eventName);
/** Sets user data */
inline void setUserData(void* data) { _userData = data; };
/** Gets user data */
inline void* getUserData() const { return _userData; };
/** Gets event name */
inline const std::string& getEventName() const { return _eventName; };
protected:
//恕我直言 没什么东西
void* _userData; ///< User data
//事件名称
std::string _eventName;
};
那再来看看 EventMouse 这个子类,也就是鼠标事件
//鼠标的操作
#define MOUSE_BUTTON_LEFT 0
#define MOUSE_BUTTON_RIGHT 1
#define MOUSE_BUTTON_MIDDLE 2
#define MOUSE_BUTTON_4 3
#define MOUSE_BUTTON_5 4
#define MOUSE_BUTTON_6 5
#define MOUSE_BUTTON_7 6
#define MOUSE_BUTTON_8 7
class CC_DLL EventMouse : public Event
{
public:
/**
* 鼠标事件类型
*/
enum class MouseEventType
{
MOUSE_NONE,
MOUSE_DOWN,
MOUSE_UP,
MOUSE_MOVE,
MOUSE_SCROLL,
};
EventMouse(MouseEventType mouseEventCode);
/** Set mouse scroll data */
inline void setScrollData(float scrollX, float scrollY) { _scrollX = scrollX; _scrollY = scrollY; };
inline float getScrollX() { return _scrollX; };
inline float getScrollY() { return _scrollY; };
//也就是 把最新的 鼠标位置保存 根据使 是否要开始捕获开始点 保存旧数据
inline void setCursorPosition(float x, float y) {
_x = x;
_y = y;
_prevPoint = _point;
_point.x = x;
_point.y = y;
if (!_startPointCaptured)
{
_startPoint = _point;
_startPointCaptured = true;
}
}
inline void setMouseButton(int button) { _mouseButton = button; };
inline int getMouseButton() { return _mouseButton; };
inline float getCursorX() { return _x; };
inline float getCursorY() { return _y; };
/** returns the current touch location in OpenGL coordinates */
Vec2 getLocation() const;
/** returns the previous touch location in OpenGL coordinates */
Vec2 getPreviousLocation() const;
/** returns the start touch location in OpenGL coordinates */
Vec2 getStartLocation() const;
/** returns the delta of 2 current touches locations in screen coordinates */
Vec2 getDelta() const;
/** returns the current touch location in screen coordinates */
Vec2 getLocationInView() const;
/** returns the previous touch location in screen coordinates */
Vec2 getPreviousLocationInView() const;
/** returns the start touch location in screen coordinates */
Vec2 getStartLocationInView() const;
private:
MouseEventType _mouseEventType;
int _mouseButton;
float _x;
float _y;
float _scrollX;
float _scrollY;
bool _startPointCaptured;
Vec2 _startPoint;
Vec2 _point;
Vec2 _prevPoint;
friend class EventListenerMouse;
};
//基本操作 没什么关键点
最后看看 EventTouch 这个类,也就是最常用的 触摸事件。
class CC_DLL EventTouch : public Event
{
public:
static const int MAX_TOUCHES = 15;
//触摸事件类型
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;
std::vector<Touch*> _touches;
friend class GLView;
};
//他的实现 没什么东西 顺便看看 Touch类
class CC_DLL Touch : public Ref
{
public:
/** how the touches are dispathced */
//分为 两种分发方式 如果你一次点击了多个点 因为人有10个手指
// 是把这些触摸点 一个个处理 还是一次处理
enum class DispatchMode {
/** All at once */
ALL_AT_ONCE,
/** one by one */
ONE_BY_ONE,
};
Touch()
: _id(0),
_startPointCaptured(false)
{}
//省略了一部分 get set
//这个 和鼠标是一样的 毕竟触摸也只是有个触摸点
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;
};
可以看到 事件本身确实定义的很简洁,更多的处理在于各个事件的监听器。
下面介绍 EventListener
class CC_DLL EventListener : public Ref
{
public:
//监听器的类型 比事件类型 多了两个
// 一个是UNKNOWN 另一个是将TOUCH 细分为两种 总的说 是一一对应的
enum class Type
{
UNKNOWN,
TOUCH_ONE_BY_ONE,
TOUCH_ALL_AT_ONCE,
KEYBOARD,
MOUSE,
ACCELERATION,
FOCUS,
GAME_CONTROLLER,
CUSTOM
};
//这个名字 其实有点误导人 ID本来单独指向 一个listener还好
//这里用来代表的是 一种类型的事件监听器
//为什么 不直接用上面的Type呢 因为 有自定义事件这个 搅*棍
//自定义事件 不知道有哪些类型的
typedef std::string ListenerID;
/** Initializes event with type and callback function */
bool init(Type t, const ListenerID& listenerID, const std::function<void(Event*)>& callback);
public:
/** Destructor */
virtual ~EventListener();
/** Checks whether the listener is available. */
virtual bool checkAvailable() = 0;
/** Clones the listener, its subclasses have to override this method. */
virtual EventListener* clone() = 0;
//值得一读
/** Enables or disables the listener
* @note Only listeners with `enabled` state will be able to receive events.
* When an listener was initialized, it's enabled by default.
* An event listener can receive events when it is enabled and is not paused.
* paused state is always false when it is a fixed priority listener.
*/
inline void setEnabled(bool enabled) { _isEnabled = enabled; };
/** Checks whether the listener is enabled */
inline bool isEnabled() const { return _isEnabled; };
protected:
//值得一读
/** Sets paused state for the listener
* The paused state is only used for scene graph priority listeners.
* `EventDispatcher::resumeAllEventListenersForTarget(node)` will set the paused state to `true`,
* while `EventDispatcher::pauseAllEventListenersForTarget(node)` will set it to `false`.
* @note 1) Fixed priority listeners will never get paused. If a fixed priority doesn't want to receive events,
* call `setEnabled(false)` instead.
* 2) In `Node`'s onEnter and onExit, the `paused state` of the listeners which associated with that node will be automatically updated.
*/
inline void setPaused(bool paused) { _paused = paused; };
/** Checks whether the listener is paused */
inline bool isPaused() const { return _paused; };
//是用来 表明是否是向 事件分发器 注册过
/** Marks the listener was registered by EventDispatcher */
inline void setRegistered(bool registered) { _isRegistered = registered; };
/** Checks whether the listener was registered by EventDispatcher */
inline bool isRegistered() const { return _isRegistered; };
/** Gets the type of this listener
* @note It's different from `EventType`, e.g. TouchEvent has two kinds of event listeners - EventListenerOneByOne, EventListenerAllAtOnce
*/
inline Type getType() const { return _type; };
/** Gets the listener ID of this listener
* When event is being dispatched, listener ID is used as key for searching listeners according to event type.
*/
inline const ListenerID& getListenerID() const { return _listenerID; };
/** Sets the fixed priority for this listener
* @note This method is only used for `fixed priority listeners`, it needs to access a non-zero value.
* 0 is reserved for scene graph priority listeners
*/
//非0值 0是给 scene graph priority 用的
inline void setFixedPriority(int fixedPriority) { _fixedPriority = fixedPriority; };
/** Gets the fixed priority of this listener
* @return 0 if it's a scene graph priority listener, non-zero for fixed priority listener
*/
inline int getFixedPriority() const { return _fixedPriority; };
/** Sets the node associated with this listener */
inline void setAssociatedNode(Node* node) { _node = node; };
/** Gets the node associated with this listener
* @return nullptr if it's a fixed priority listener, otherwise return non-nullptr
*/
//fixed priority listener 将会返回null 因为他未与node绑定
inline Node* getAssociatedNode() const { return _node; };
///////////////
// Properties
//////////////
//仿函数 实现回调 很方便 前面几篇的 Schedule也是使用这种方式
//特别是对于 lambda 成员函数 会特别方便
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;
};
照例 还是先看看 EventListenerCustom
//一如既往的 没什么看头
class CC_DLL EventListenerCustom : public EventListener
{
public:
/** Creates an event listener with type and callback.
* @param eventType The type of the event.
* @param callback The callback function when the specified event was emitted.
*/
static EventListenerCustom* create(const std::string& eventName, const std::function<void(EventCustom*)>& callback);
/// Overrides
virtual bool checkAvailable() override;
virtual EventListenerCustom* clone() override;
CC_CONSTRUCTOR_ACCESS:
/** Constructor */
EventListenerCustom();
/** Initializes event with type and callback function */
bool init(const ListenerID& listenerId, const std::function<void(EventCustom*)>& callback);
protected:
//
std::function<void(EventCustom*)> _onCustomEvent;
friend class LuaEventListenerCustom;
};
//实现
EventListenerCustom* EventListenerCustom::create(const std::string& eventName, const std::function<void(EventCustom*)>& callback)
{
EventListenerCustom* ret = new (std::nothrow) EventListenerCustom();
if (ret && ret->init(eventName, callback))
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
bool EventListenerCustom::init(const ListenerID& listenerId, const std::function<void(EventCustom*)>& callback)
{
bool ret = false;
_onCustomEvent = callback;
//包装成 接受 Event* event的lambda
auto listener = [this](Event* event){
if (_onCustomEvent != nullptr)
{
_onCustomEvent(static_cast<EventCustom*>(event));
}
};
//为上层(事件分发器)提供统一的接口
if (EventListener::init(EventListener::Type::CUSTOM, listenerId, listener))
{
ret = true;
}
return ret;
}
继续看看 EventListenerMouse
class CC_DLL EventListenerMouse : public EventListener
{
public:
// listenerid 是代表 这个类型listerner的监听器
//之所以 EventListenerCustom 没有这一项
// 自定义监听器 每个传入的 name都代表 一种类型事件以及事件监听器
static const std::string LISTENER_ID;
static EventListenerMouse* create();
/// Overrides
virtual EventListenerMouse* clone() override;
virtual bool checkAvailable() override;
//主要的 对应四个事件类型的 处理
std::function<void(Event* event)> onMouseDown;
std::function<void(Event* event)> onMouseUp;
std::function<void(Event* event)> onMouseMove;
std::function<void(Event* event)> onMouseScroll;
CC_CONSTRUCTOR_ACCESS:
EventListenerMouse();
bool init();
};
//实现
const std::string EventListenerMouse::LISTENER_ID = "__cc_mouse";
bool EventListenerMouse::checkAvailable()
{
return true;
}
EventListenerMouse* EventListenerMouse::create()
{
auto ret = new (std::nothrow) EventListenerMouse();
if (ret && ret->init())
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
EventListenerMouse* EventListenerMouse::clone()
{
auto ret = new (std::nothrow) EventListenerMouse();
if (ret && ret->init())
{
ret->autorelease();
ret->onMouseUp = onMouseUp;
ret->onMouseDown = onMouseDown;
ret->onMouseMove = onMouseMove;
ret->onMouseScroll = onMouseScroll;
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
EventListenerMouse::EventListenerMouse()
: onMouseDown(nullptr)
, onMouseUp(nullptr)
, onMouseMove(nullptr)
, onMouseScroll(nullptr)
{
}
//这个 就是 对应于每个 时间类型 调用相应的回调函数
//对上层 包装成 统一接口
bool EventListenerMouse::init()
{
auto listener = [this](Event* event){
auto mouseEvent = static_cast<EventMouse*>(event);
switch (mouseEvent->_mouseEventType)
{
case EventMouse::MouseEventType::MOUSE_DOWN:
if(onMouseDown != nullptr)
onMouseDown(event);
break;
case EventMouse::MouseEventType::MOUSE_UP:
if(onMouseUp != nullptr)
onMouseUp(event);
break;
case EventMouse::MouseEventType::MOUSE_MOVE:
if(onMouseMove != nullptr)
onMouseMove(event);
break;
case EventMouse::MouseEventType::MOUSE_SCROLL:
if(onMouseScroll != nullptr)
onMouseScroll(event);
break;
default:
break;
}
};
if (EventListener::init(Type::MOUSE, LISTENER_ID, listener))
{
return true;
}
return false;
}
最后看看 最重要的 最常用 EventListenerTouchOneByOne 和 EventListenerTouchAllAtOnce
class CC_DLL EventListenerTouchOneByOne : public EventListener
{
public:
static const std::string LISTENER_ID;
static EventListenerTouchOneByOne* create();
virtual ~EventListenerTouchOneByOne();
//是否吞噬 事件 就是自己处理完了 后面的就没得处理了
void setSwallowTouches(bool needSwallow);
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;
};
//具体实现
const std::string EventListenerTouchOneByOne::LISTENER_ID = "__cc_touch_one_by_one";
//这里没有对各个处理的函数进行封装
//应该是 这个情况比较复杂
// 那只有等到 事件分发的时候 具体情况调用
bool EventListenerTouchOneByOne::init()
{
if (EventListener::init(Type::TOUCH_ONE_BY_ONE, LISTENER_ID, nullptr))
{
return true;
}
return false;
}
//可以看到 并没有要求 create的时候传入 相关回调函数 因为这几个是 public 可以直接访问
EventListenerTouchOneByOne* EventListenerTouchOneByOne::create()
{
auto ret = new (std::nothrow) EventListenerTouchOneByOne();
if (ret && ret->init())
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
bool EventListenerTouchOneByOne::checkAvailable()
{
// EventDispatcher will use the return value of 'onTouchBegan' to determine whether to pass following 'move', 'end'
// message to 'EventListenerTouchOneByOne' or not. So 'onTouchBegan' needs to be set.
if (onTouchBegan == nullptr)
{
CCASSERT(false, "Invalid EventListenerTouchOneByOne!");
return false;
}
return true;
}
EventListenerTouchOneByOne* EventListenerTouchOneByOne::clone()
{
auto ret = new (std::nothrow) EventListenerTouchOneByOne();
if (ret && ret->init())
{
ret->autorelease();
ret->onTouchBegan = onTouchBegan;
ret->onTouchMoved = onTouchMoved;
ret->onTouchEnded = onTouchEnded;
ret->onTouchCancelled = onTouchCancelled;
ret->_claimedTouches = _claimedTouches;
ret->_needSwallow = _needSwallow;
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
//同理 EventListenerTouchAllAtOnce 中也没有什么具体细节 和上面类似
//也应该在 具体调用的时候 来处理
到了关键的 EventDispatcher分析
其实可想而知 他负责将各种 注册的listener组织起来 ,然后当有模块发布了事件 就相应的找到 listener,然后回调其函数即可。

具体类的重要代码如下:
class CC_DLL EventDispatcher : public Ref
{
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);
/** Adds a event listener for a specified event with the fixed priority.
* @param listener The listener of a specified event.
* @param fixedPriority The fixed priority of the listener.
* @note A lower priority will be called before the ones that have a higher value.
* 0 priority is forbidden for fixed priority since it's used for scene graph based priority.
*/
//固定优先级 加入listener
void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);
/** Adds a Custom event listener.
It will use a fixed priority of 1.
@return the generated event. Needed in order to remove the event from the dispather
*/
//添加 自定义的listener
EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);
void dispatchEvent(Event* event);
/** Dispatches a Custom Event with a event name an optional user data */
//分发 自定义事件
void dispatchCustomEvent(const std::string &eventName, void *optionalUserData = nullptr);
//其中 有个内部类 就是对vector
//实际上 对应于一个listenID 即为一个事件类型
//对应于 一个 EventListenerVector
class EventListenerVector
{
public:
EventListenerVector();
~EventListenerVector();
size_t size() const;
bool empty() const;
void push_back(EventListener* item);
void clearSceneGraphListeners();
void clearFixedListeners();
void clear();
inline std::vector<EventListener*>* getFixedPriorityListeners() const { return _fixedListeners; };
inline std::vector<EventListener*>* getSceneGraphPriorityListeners() const { return _sceneGraphListeners; };
inline ssize_t getGt0Index() const { return _gt0Index; };
inline void setGt0Index(ssize_t index) { _gt0Index = index; };
private:
std::vector<EventListener*>* _fixedListeners;
std::vector<EventListener*>* _sceneGraphListeners;
//第一个 大于等于0的 位置
ssize_t _gt0Index;
};
//添加 EventListener 内部实现 肯定根据 类型调用不同的函数
void addEventListener(EventListener* listener);
/** Force adding an event listener
* @note force add an event listener which will ignore whether it's in dispatching.
* @see addEventListener
*/
//强行 添加一个 EventListener
void forceAddEventListener(EventListener* listener);
/** Touch event needs to be processed different with other events since it needs support ALL_AT_ONCE and ONE_BY_NONE mode. */
//分发 触摸事件 其内部必然 分两种处理方式
void dispatchTouchEvent(EventTouch* event);
//偷来的一段话
//DirtyFlag 是设置给 ListenerID 的,每当新添加一个 Listener,或则删除一个 Listener 的时候,
//就会给当前 Listener 的 ListenerID 添加一个
//DirtyFlag。说明这个脏是指 ListenerID 对应的监听器向量列表需要重新排序了,如果不脏就不需要排序。
/// Priority dirty flag
enum class DirtyFlag
{
NONE = 0,
FIXED_PRIORITY = 1 << 0,
SCENE_GRAPH_PRIORITY = 1 << 1,
ALL = FIXED_PRIORITY | SCENE_GRAPH_PRIORITY
};
/** Sets the dirty flag for a specified listener ID */
void setDirty(const EventListener::ListenerID& listenerID, DirtyFlag flag);
//通过SceneGraph来获取每个节点的绘制顺序,在使用SceneGraph优先级对事件侦听器进行排序之前调用它
void visitTarget(Node* node, bool isRootNode);
//重要的数据结构
//ListenerID 与 EventListenerVector的 map
//即为 不同类型的 listener 存在不同位置
/** Listeners map */
std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;
//用来表明 ListenerID对应的 EventListenerVector的那一部分 listener脏了 需要重新排序
/** The map of dirty flag */
std::unordered_map<EventListener::ListenerID, DirtyFlag> _priorityDirtyFlagMap;
//Node节点与其对应EventListener 数组,应该用在 SceneGraphPriority
/** The map of node and event listeners */
std::unordered_map<Node*, std::vector<EventListener*>*> _nodeListenersMap;
//节点与其对应的优先级
/** The map of node and its event priority */
std::unordered_map<Node*, int> _nodePriorityMap;
//z序与其对应的Node节点们
/** key: Global Z Order, value: Sorted Nodes */
std::unordered_map<float, std::vector<Node*>> _globalZOrderNodeMap;
//这次事件分发后 将要的 加入 listener
/** The listeners to be added after dispatching event */
std::vector<EventListener*> _toAddedListeners;
/** The nodes were associated with scene graph based priority listeners */
//与基于SceneGraphPriority的listener 有关联的 node
std::set<Node*> _dirtyNodes;
/** Whether the dispatcher is dispatching event */
int _inDispatch;
/** Whether to enable dispatching event */
bool _isEnabled;
int _nodePriorityIndex;
std::set<std::string> _internalCustomListenerIDs;
};
这部分代码比较长,具体该类的实现继续说:
//添加 SceneGraphPriority listener 传入对应的 node
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
CCASSERT(listener && node, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
if (!listener->checkAvailable())
return;
//设置 对应的node
listener->setAssociatedNode(node);
//其实这里可以看出来 SceneGraphPriority就是 优先级为0
//并且多了个 AssociatedNode
listener->setFixedPriority(0);
listener->setRegistered(true);
addEventListener(listener);
}
//添加 固定优先级的 listener
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
CCASSERT(listener, "Invalid parameters.");
CCASSERT(!listener->isRegistered(), "The listener has been registered.");
CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority.");
if (!listener->checkAvailable())
return;
//没有 关联的对象
listener->setAssociatedNode(nullptr);
listener->setFixedPriority(fixedPriority);
listener->setRegistered(true);
listener->setPaused(false);
//底层都是调用了 addEventListener
addEventListener(listener);
}
//添加 自定义的 listener
EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)
{
EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);
//只是设置为 优先级 设为1 也算高了
//然后当做 固定优先级 添加 真是低调
addEventListenerWithFixedPriority(listener, 1);
return listener;
}
//添加 EventListener
void EventDispatcher::addEventListener(EventListener* listener)
{
//直接 添加 listener
if (_inDispatch == 0)
{
forceAddEventListener(listener);
}
//如果正在分发事件 就先存着
else
{
_toAddedListeners.push_back(listener);
}
listener->retain();
}
void EventDispatcher::forceAddEventListener(EventListener* listener)
{
EventListenerVector* listeners = nullptr;
//先看看 有没有 这种类型的 ListenerID 对应的EventListenerVector
EventListener::ListenerID listenerID = listener->getListenerID();
auto itr = _listenerMap.find(listenerID);
//没有的话 就新建
if (itr == _listenerMap.end())
{
listeners = new (std::nothrow) EventListenerVector();
_listenerMap.insert(std::make_pair(listenerID, listeners));
}
else
{
listeners = itr->second;
}
//这里push_back有个讲究 代码没贴 大概的意思是
//如果 优先级为 0 就是 sceneGraphListeners
//否则就加入到 另外一条中
listeners->push_back(listener);
//如果 优先级为 0 就说明 对于 listenerID的 SCENE_GRAPH_PRIORITY这部分更新了 脏了
if (listener->getFixedPriority() == 0)
{
setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY);
auto node = listener->getAssociatedNode();
CCASSERT(node != nullptr, "Invalid scene graph priority!");
associateNodeAndEventListener(node, listener);
if (node->isRunning())
{
resumeEventListenersForTarget(node);
}
}
else
{
//否则 就是 另外一部分 脏了
setDirty(listenerID, DirtyFlag::FIXED_PRIORITY);
}
}
//就是 把 node与EventListener的对应 存起来
void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener)
{
std::vector<EventListener*>* listeners = nullptr;
auto found = _nodeListenersMap.find(node);
if (found != _nodeListenersMap.end())
{
listeners = found->second;
}
else
{
listeners = new std::vector<EventListener*>();
_nodeListenersMap.insert(std::make_pair(node, listeners));
}
listeners->push_back(listener);
}
下面正式开始 介绍Dispatch的逻辑
//分发 自定义事件 简单包装一下 交由dispatchEvent
void EventDispatcher::dispatchCustomEvent(const std::string &eventName, void *optionalUserData)
{
EventCustom ev(eventName);
ev.setUserData(optionalUserData);
dispatchEvent(&ev);
}
//最核心的 dispatchEvent
void EventDispatcher::dispatchEvent(Event* event)
{
if (!_isEnabled)
return;
//不值得 展开讲
//就是 将_dirtyNodes 也就是对应 与 SceneGraph有关的 node
//找到 其对应的 listener数组
//对每一个 listener 标记其 SceneGraph 脏了 需要更新
//针对的是 新添加的 node相关 处理完 这个_dirtyNodes 会清空
updateDirtyFlagForSceneGraph();
DispatchGuard guard(_inDispatch);
//单独处理 触摸事件
if (event->getType() == Event::Type::TOUCH)
{
dispatchTouchEvent(static_cast<EventTouch*>(event));
return;
}
//找出 这种事件类型的 对应的 listenerid
auto listenerID = __getListenerID(event);
//排序 listener
sortEventListeners(listenerID);
auto iter = _listenerMap.find(listenerID);
if (iter != _listenerMap.end())
{
auto listeners = iter->second;
auto onEvent = [&event](EventListener* listener) -> bool{
event->setCurrentTarget(listener->getAssociatedNode());
listener->_onEvent(event);
return event->isStopped();
};
//直接 分发事件
dispatchEventToListeners(listeners, onEvent);
}
updateListeners(event);
}
// 先说 排序
void EventDispatcher::sortEventListeners(const EventListener::ListenerID& listenerID)
{
DirtyFlag dirtyFlag = DirtyFlag::NONE;
auto dirtyIter = _priorityDirtyFlagMap.find(listenerID);
if (dirtyIter != _priorityDirtyFlagMap.end())
{
dirtyFlag = dirtyIter->second;
}
//这就是 如果数据没脏就不排序
if (dirtyFlag != DirtyFlag::NONE)
{
// Clear the dirty flag first, if `rootNode` is nullptr, then set its dirty flag of scene graph priority
dirtyIter->second = DirtyFlag::NONE;
if ((int)dirtyFlag & (int)DirtyFlag::FIXED_PRIORITY)
{
//先排序 固定 优先级的
sortEventListenersOfFixedPriority(listenerID);
}
if ((int)dirtyFlag & (int)DirtyFlag::SCENE_GRAPH_PRIORITY)
{
auto rootNode = Director::getInstance()->getRunningScene();
if (rootNode)
{
//再排序 SceneGraphPriority
sortEventListenersOfSceneGraphPriority(listenerID, rootNode);
}
else
{
dirtyIter->second = DirtyFlag::SCENE_GRAPH_PRIORITY;
}
}
}
}
//继续深究 这两种 排序
void EventDispatcher::sortEventListenersOfFixedPriority(const EventListener::ListenerID& listenerID)
{
auto listeners = getListeners(listenerID);
if (listeners == nullptr)
return;
auto fixedListeners = listeners->getFixedPriorityListeners();
if (fixedListeners == nullptr)
return;
// After sort: priority < 0, > 0
//先排个序 按优先级 从小到大
std::sort(fixedListeners->begin(), fixedListeners->end(), [](const EventListener* l1, const EventListener* l2) {
return l1->getFixedPriority() < l2->getFixedPriority();
});
// FIXME: Should use binary search
//找到 第一个>0的位置
//因为 最后的顺序是 先 <0 再 SceneGraphPriority 即为0
//再分发 >0
int index = 0;
for (auto& listener : *fixedListeners)
{
if (listener->getFixedPriority() >= 0)
break;
++index;
}
listeners->setGt0Index(index);
}
void EventDispatcher::sortEventListenersOfSceneGraphPriority(const EventListener::ListenerID& listenerID, Node* rootNode)
{
auto listeners = getListeners(listenerID);
if (listeners == nullptr)
return;
auto sceneGraphListeners = listeners->getSceneGraphPriorityListeners();
if (sceneGraphListeners == nullptr)
return;
// Reset priority index
_nodePriorityIndex = 0;
//清空节点 优先级
_nodePriorityMap.clear();
//遍历 rootNode
visitTarget(rootNode, true);
// After sort: priority < 0, > 0
//根据节点的优先级来 排序sceneGraphListeners
std::sort(sceneGraphListeners->begin(), sceneGraphListeners->end(), [this](const EventListener* l1, const EventListener* l2) {
return _nodePriorityMap[l1->getAssociatedNode()] > _nodePriorityMap[l2->getAssociatedNode()];
});
}
//看看 visitTarget
void EventDispatcher::visitTarget(Node* node, bool isRootNode)
{
int i = 0;
auto& children = node->getChildren();
auto childrenCount = children.size();
if(childrenCount > 0)
{
Node* child = nullptr;
// visit children zOrder < 0
for( ; i < childrenCount; i++ )
{
child = children.at(i);
if ( child && child->getLocalZOrder() < 0 )
//递归遍历 child->getLocalZOrder() < 0
visitTarget(child, false);
else
break;
}
//如果某个节点对应了 listener
if (_nodeListenersMap.find(node) != _nodeListenersMap.end())
{
//将其 添加到 GlobalZOrder对应的数组
_globalZOrderNodeMap[node->getGlobalZOrder()].push_back(node);
}
//访问 另一部分 大于0的部分
for( ; i < childrenCount; i++ )
{
child = children.at(i);
if (child)
visitTarget(child, false);
}
}
else
{
//叶子节点 直接加入
if (_nodeListenersMap.find(node) != _nodeListenersMap.end())
{
_globalZOrderNodeMap[node->getGlobalZOrder()].push_back(node);
}
}
//根节点 也就是最后一次调用的时候 整个遍历结束了
if (isRootNode)
{
std::vector<float> globalZOrders;
globalZOrders.reserve(_globalZOrderNodeMap.size());
for (const auto& e : _globalZOrderNodeMap)
{
globalZOrders.push_back(e.first);
}
//排序所有的Zorder 从小大大 要知道 z越小 离屏幕越近
std::sort(globalZOrders.begin(), globalZOrders.end(), [](const float a, const float b){
return a < b;
});
for (const auto& globalZ : globalZOrders)
{
for (const auto& n : _globalZOrderNodeMap[globalZ])
{ //按照不同Zorder 同一Zorder 从左到右 计数
//此时 顺序已经定了
_nodePriorityMap[n] = ++_nodePriorityIndex;
}
}
_globalZOrderNodeMap.clear();
}
}
//这时候再提 dispatchEventToListeners 触摸相关的一会儿说
void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
{
bool shouldStopPropagation = false;
//获取两个 listener 列表
auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
ssize_t i = 0;
//下面分别 按照 priority < 0 priority == 0, >0 遍历 处理
//注意的是 只要有listener处理了 并且吞吃了 就不会往后传递了 所以优先级的意义在这里
// priority < 0
if (fixedPriorityListeners)
{
CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");
if (!fixedPriorityListeners->empty())
{
for (; i < listeners->getGt0Index(); ++i)
{
auto l = fixedPriorityListeners->at(i);
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
}
if (sceneGraphPriorityListeners)
{
if (!shouldStopPropagation)
{
// priority == 0, scene graph priority
for (auto& l : *sceneGraphPriorityListeners)
{
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
}
if (fixedPriorityListeners)
{
if (!shouldStopPropagation)
{
// priority > 0
ssize_t size = fixedPriorityListeners->size();
for (; i < size; ++i)
{
auto l = fixedPriorityListeners->at(i);
if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
{
shouldStopPropagation = true;
break;
}
}
}
}
}
单独提出来 对touch的处理,太长了 也很有意思
void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
//排个序
sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
// If there aren't any touch listeners, return directly.
if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)
return;
bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners);
const std::vector<Touch*>& originalTouches = event->getTouches();
//复制 一份
std::vector<Touch*> mutableTouches(originalTouches.size());
std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin());
//
// process the target handlers 1st
//
//优先处理 onebyone
if (oneByOneListeners)
{
auto mutableTouchesIter = mutableTouches.begin();
auto touchesIter = originalTouches.begin();
for (; touchesIter != originalTouches.end(); ++touchesIter)
{
bool isSwallowed = false;
auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break
EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l);
// Skip if the listener was removed.
if (!listener->_isRegistered)
return false;
event->setCurrentTarget(listener->_node);
bool isClaimed = false;
std::vector<Touch*>::iterator removedIter;
EventTouch::EventCode eventCode = event->getEventCode();
if (eventCode == EventTouch::EventCode::BEGAN)
{
if (listener->onTouchBegan)
{
//说明这个触摸点 他可以处理 收下了
isClaimed = listener->onTouchBegan(*touchesIter, event);
if (isClaimed && listener->_isRegistered)
{
listener->_claimedTouches.push_back(*touchesIter);
}
}
}
//不是 begin事件 begin时候已经记录了所有要处理的触摸点
//后续就是要确保 还是以前 触摸点
//注意一个触摸点 并非是一个坐标 是手指点击到屏幕 滑动 直到离开
//这看成一次完完整的触摸 其坐标都记录在这一个触摸点对象中
else if (listener->_claimedTouches.size() > 0
&& ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
{
isClaimed = true;
switch (eventCode)
{
case EventTouch::EventCode::MOVED:
if (listener->onTouchMoved)
{
listener->onTouchMoved(*touchesIter, event);
}
break;
case EventTouch::EventCode::ENDED:
if (listener->onTouchEnded)
{
listener->onTouchEnded(*touchesIter, event);
}
//结束了 就从 listener删掉这个触摸点
if (listener->_isRegistered)
{
listener->_claimedTouches.erase(removedIter);
}
break;
case EventTouch::EventCode::CANCELLED:
if (listener->onTouchCancelled)
{
listener->onTouchCancelled(*touchesIter, event);
}
if (listener->_isRegistered)
{
listener->_claimedTouches.erase(removedIter);
}
break;
default:
CCASSERT(false, "The eventcode is invalid.");
break;
}
}
// If the event was stopped, return directly.
//事件被stop了
if (event->isStopped())
{
updateListeners(event);
return true;
}
CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), "");
//如果这个触摸点 oneByOneListeners愿意处理 并且 _needSwallow就从触摸点列表中删掉
// 后续listener就没机会 处理了
if (isClaimed && listener->_isRegistered && listener->_needSwallow)
{
if (isNeedsMutableSet)
{
mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);
isSwallowed = true;
}
return true;
}
return false;
};
//
dispatchEventToListeners(oneByOneListeners, onTouchEvent);
if (event->isStopped())
{
return;
}
//吞了的话 迭代器已经自动更新了 所以不必自加
if (!isSwallowed)
++mutableTouchesIter;
}
}
//
// process standard handlers 2nd
//
//最后 如果还剩下什么 点 就给 allAtOnceListeners 处理
if (allAtOnceListeners && mutableTouches.size() > 0)
{
auto onTouchesEvent = [&](EventListener* l) -> bool{
EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l);
// Skip if the listener was removed.
if (!listener->_isRegistered)
return false;
event->setCurrentTarget(listener->_node);
//allAtOnceListeners 果然不同 一次处理多个触摸点操作
//而且 他也没有 有始有终 的意味 不必要第一次返回bool的操作
switch (event->getEventCode())
{
case EventTouch::EventCode::BEGAN:
if (listener->onTouchesBegan)
{
listener->onTouchesBegan(mutableTouches, event);
}
break;
case EventTouch::EventCode::MOVED:
if (listener->onTouchesMoved)
{
listener->onTouchesMoved(mutableTouches, event);
}
break;
case EventTouch::EventCode::ENDED:
if (listener->onTouchesEnded)
{
listener->onTouchesEnded(mutableTouches, event);
}
break;
case EventTouch::EventCode::CANCELLED:
if (listener->onTouchesCancelled)
{
listener->onTouchesCancelled(mutableTouches, event);
}
break;
default:
CCASSERT(false, "The eventcode is invalid.");
break;
}
// If the event was stopped, return directly.
if (event->isStopped())
{
updateListeners(event);
return true;
}
return false;
};
dispatchEventToListeners(allAtOnceListeners, onTouchesEvent);
if (event->isStopped())
{
return;
}
}
updateListeners(event);
}
最后简要介绍 updateListeners
//其实就是 根据事件的类型 更新对应种类listenerID的所有监听器
//如果注册状态 为 未注册 测删掉对应监听器
//如果 更新后发现 整个种类都没了 就删除这一类的 表项
//同时 如果正在分发事件的最后 还可以把_toAddedListeners加入过来
void EventDispatcher::updateListeners(Event* event)
{
CCASSERT(_inDispatch > 0, "If program goes here, there should be event in dispatch.");
auto onUpdateListeners = [this](const EventListener::ListenerID& listenerID)
{
auto listenersIter = _listenerMap.find(listenerID);
if (listenersIter == _listenerMap.end())
return;
auto listeners = listenersIter->second;
auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
if (sceneGraphPriorityListeners)
{
for (auto iter = sceneGraphPriorityListeners->begin(); iter != sceneGraphPriorityListeners->end();)
{
auto l = *iter;
if (!l->isRegistered())
{
iter = sceneGraphPriorityListeners->erase(iter);
l->release();
}
else
{
++iter;
}
}
}
if (fixedPriorityListeners)
{
for (auto iter = fixedPriorityListeners->begin(); iter != fixedPriorityListeners->end();)
{
auto l = *iter;
if (!l->isRegistered())
{
iter = fixedPriorityListeners->erase(iter);
l->release();
}
else
{
++iter;
}
}
}
if (sceneGraphPriorityListeners && sceneGraphPriorityListeners->empty())
{
listeners->clearSceneGraphListeners();
}
if (fixedPriorityListeners && fixedPriorityListeners->empty())
{
listeners->clearFixedListeners();
}
};
if (event->getType() == Event::Type::TOUCH)
{
onUpdateListeners(EventListenerTouchOneByOne::LISTENER_ID);
onUpdateListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
}
else
{
onUpdateListeners(__getListenerID(event));
}
if (_inDispatch > 1)
return;
CCASSERT(_inDispatch == 1, "_inDispatch should be 1 here.");
for (auto iter = _listenerMap.begin(); iter != _listenerMap.end();)
{
if (iter->second->empty())
{
_priorityDirtyFlagMap.erase(iter->first);
delete iter->second;
iter = _listenerMap.erase(iter);
}
else
{
++iter;
}
}
if (!_toAddedListeners.empty())
{
for (auto& listener : _toAddedListeners)
{
forceAddEventListener(listener);
}
_toAddedListeners.clear();
}
}
最后
下一篇 就 Node 类体系展开分析。
本文详细分析了cocos2d-x中的EventDispatcher类,从Event基类开始,逐步讲解了EventCustom、EventMouse、EventTouch子类,以及EventListener的各个子类如EventListenerCustom、EventListenerMouse、EventListenerTouchOneByOne和EventListenerTouchAllAtOnce。重点阐述了EventDispatcher如何组织并处理注册的监听器,当事件发生时如何调用相应回调。此外,还特别讨论了触摸事件的处理逻辑和updateListeners方法。

1155

被折叠的 条评论
为什么被折叠?



