事件和监听器

cocos2dx 3.0 中事件和监听器,结合CCEventCCEventListener的代码

Event Listener
TOUCH TOUCH_ONE_BY_ONE
TOUCH_ALL_AT_ONCE
KEYBOARD KEYBOARD
ACCELERATION ACCELERATION
MOUSE MOUSE
CUSTOM CUSTOM

EventListener::Type中还有一个UNKNOW

对于手机客户端来说,最常用的便是TouchEvent和AccelerationEvent

触摸

对于EventListenerTouch,这里有两种类型:

EventListenerTouchOneByOne

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class EventListenerTouchOneByOne : public EventListener
{
public:
static const std::string LISTENER_ID;

...

void setSwallowTouches(bool needSwallow);
bool isSwallowTouches();

...

public:
/* std::function的参数类型是`Touch*`和`Event*` */
std::function<bool(Touch*, Event*)> onTouchBegan;
std::function<void(Touch*, Event*)> onTouchMoved;
std::function<void(Touch*, Event*)> onTouchEnded;
std::function<void(Touch*, Event*)> onTouchCancelled;

private:
...

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

friend class EventDispatcher;
};

其实最关键的一句话就是friend class EventDispatcher;
所有的操作都是在EventDispatcher中操作,所以重点分析的还是EventDispatcher

EventListenerTouchAllAtOnce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class EventListenerTouchAllAtOnce : public EventListener
{
public:
static const std::string LISTENER_ID;

...

public:
/* std::function的参数类型是`std::vector<Touch*>`和`Event*` */
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesBegan;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesMoved;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesEnded;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesCancelled;

private:
friend class EventDispatcher;
};

和EventListenerTouchOneByOne的区别在于不可吞噬,还有就是回调函数的区别

分发器

成员变量

接下来便是成员变量,这里面有太多的表和集合,第一时间还不是很知道在搞毛。

1
2
3
4
5
6
7
enum class DirtyFlag
{
NONE = 0,
FIXED_PRIORITY = 1 << 0,
SCENE_GRAPH_PRIORITY = 1 << 1,
ALL = FIXED_PRIORITY | SCENE_GRAPH_PRIORITY
};
Type Name Usage
<string, EventListenerVector*> _listenerMap 查找这种监听器对应的监听器数组
<ListenerID, DirtyFlag> _priorityDirtyFlagMap; 表示这种监听器的标志位类别
<Node*, vector<EventListener*>*> _nodeListenersMap; 根据Node去查找对应的监听器数组
<Node*, int> _nodePriorityMap; 根据Node查找优先级表,用于排序
<float, vector<Node*>> _globalZOrderNodeMap; 根据全局Z轴查找的Node节点数组,用于生成_nodePriorityMap
vector<EventListener*> _toAddedListeners; 待加加入分发数组的监听器
set<Node*> _dirtyNodes; 待更新标识的显示顺序监听器
int _inDispatch; 在分发中的事件个数
bool _isEnabled; 是否开启事件分发
int _nodePriorityIndex 在生成_nodePriorityMap的时候的公共索引
set<string> _internalCustomListenerIDs

EventListenerVector

先看一个Dispatcher的内置类EventListenerVector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;

/* _fixedListeners中优先级为0的开始下标 */
ssize_t _gt0Index;
};

这个EventListenerVector实际上就是管理两个std::vector

  • 带有优先级的监听器 (_fixedListeners)
  • 按显示顺序的监听器 (_sceneGraphListeners)

Event内置类型

Event ListenerID
EventListenerTouchOneByOne __cc_touch_one_by_one
EventListenerTouchAllAtOnce __cc_touch_all_at_once
EventListenerKeyBoard __cc_keyboard
EventListenerMouse __cc_mouse
EventListenerAcceleration __cc_acceleration

添加监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* Listener, Node *node)
{
if (!listener->checkAvailable()) return;

/* 需要设置关联的Node节点 */
listener->setAssociatedNode(node);

/* 对于按现实顺序的监听器预留的 0 */
listener->setFixedPriority(0);

listener->setRegistered(true);
addEventListener(listener);
}

void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
if (!listener->checkAvailable()) return;

listener->setAssociatedNode(nullptr);
listener->setFixedPriority(fixedPriority);
listener->setRegistered(true);

/* EventListener的默认值是true */
listener->setPaused(false);

addEventListener(listener);
}

EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)
{
EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);
addEventListenerWithFixedPriority(listener, 1);
return listener;
}

void EventDispatcher::addEventListener(EventListener* listener)
{
if (_inDispatch == 0)
{
/* 若当前没有在分发事件,则将该监听器加入到分发中 */
forceAddEventListener(listener);
}
else
{
/* 若当前正在分发事件,则将监听器加入到待添加数组_toAddedListeners中 */
/* 在分发事件结束时,调用updateListeners再将监听器加入到分发中 */
_toAddedListeners.push_back(listener);
}

listener->retain();
}

void EventDispatcher::forceAddEventListener(EventListener* listener)
{
EventListenerVector* listeners = nullptr;
EventListener::ListenerID listenerID = listener->getListenerID();

/* 根据监听器种类查找对应监听器数组 */

auto itr = _listenerMap.find(listenerID);
if (itr == _listenerMap.end()) /* 若没有找到该监听器数组 */
{
/* 新建一个监听器数组,并加入到监听器数组表中 */
listeners = new EventListenerVector();
_listenerMap.insert(std::make_pair(listenerID, listeners));
}
else
{
listeners = itr->second;
}

/* 将监听器加入到这类监听器数组中 */
listeners->push_back(listener);

if (listener->getFixedPriority() == 0) /* 若是按显示顺序的监听器 */
{
/* 设置标识,加入到_priorityDirtyFlagMap */
setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY);

auto node = listener->getAssociatedNode();
CCASSERT(node != nullptr, "Invalid scene graph priority!");

/* 关联该节点和这个监听器*/
/* 即将该监听器加入到 _nodeListenersMap 中 */
associateNodeAndEventListener(node, listener);

if (node->isRunning())
{
/* 将node加入_dirtyNodes */
resumeEventListenersForTarget(node);
}
}
else /* 若是全局优先级的监听器,仅仅只要设置标识即可 */
{
setDirty(listenerID, DirtyFlag::FIXED_PRIORITY);
}
}

为啥对于按显示顺序的监听器不需要setPaused(false)?

对于这类监听器,setPaused是会在onEnter和onExit的过程中调用到。
(详见Node::resume && Node::pause)
(最后还是调用EventDispatcher::pauseEventListenersForTarget, EventDispatcher::resumeEventListenersForTarget)

EventDispatcher::resumeEventListenersForTarget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void EventDispatcher::resumeEventListenersForTarget(Node* target, bool recursive/* = false */)
{
auto listenerIter = _nodeListenersMap.find(target);
if (listenerIter != _nodeListenersMap.end())
{
auto listeners = listenerIter->second;
for (auto& l : *listeners) l->setPaused(false);
}

/* 这也是个递归调用,基本上就是把Node加入_dirtyNodes中 */
setDirtyForNode(target);

/* 这边是一个递归调用 */
if (recursive)
{
const auto& children = target->getChildren();
for (const auto& child : children) resumeEventListenersForTarget(child, true);
}
}

事件分发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void EventDispatcher::dispatchEvent(Event* event)
{
if (!_isEnabled) return;

/* 这里主要是遍历_dirtyNodes */
/* 根据_dirtyNodes去更新Node*节点的DirtyFlag */
updateDirtyFlagForSceneGraph();

/* 增加_inDispatch的计数 */
/* 当这个分发函数执行完毕的时候,会调用析构函数减少_inDispatch的计数 */
DispatchGuard guard(_inDispatch);

/* 单独将触摸事件独立处理 */
if (event->getType() == Event::Type::TOUCH)
{
dispatchTouchEvent(static_cast<EventTouch*>(event));
/* 在这个函数结束调用之后,栈对象guard会调用析构函数 */
return;
}

/* 获得事件类型 */
auto listenerID = __getListenerID(event);

/* 对监听器进行排序 */
/* 会对_fixedListeners或_sceneGraphListeners进行排序 */
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);
}

/* 更新监听器列表 */
/* 在这个函数中会检查_inDispatch的值 */
/* 根据_inDispatch的值,会对_toAddedListeners进行操作 */
updateListeners(event);

/* 在这个函数结束调用之后,栈对象guard会调用析构函数 */
}

分发触摸事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
/* 先是排序 */
/* 这里的排序是根据_priorityDirtyFlagMap中查询到的DirtyFlag进行相应排序 */
/* 若是根据显示顺序的监听器的话,通过visitTarget重新获取_nodePriorityMap*/
/* 若是根据全局优先级的监听器的话,则只需要根据优先级进行排序即可 */
sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);

auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);

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());

/* 先处理单点触控 */
if (oneByOneListeners)
{
auto mutableTouchesIter = mutableTouches.begin();
auto touchesIter = originalTouches.begin();

for (; touchesIter != originalTouches.end(); ++touchesIter)
{
bool isSwallowed = false;

/* 给该监听器分发一个单点触控事件 */
/* 改lambda表达式可能对isSwallowed进行修改 */
/* 若是开启了吞噬,则会在调用过程中将这个吞噬掉的touch从mutableTouches中移除 */
auto onTouchEvent = [&](EventListener* l) -> bool { ... };

dispatchEventToListeners(oneByOneListeners, onTouchEvent);

if (event->isStopped()) return;

/* 若没有设置触摸 */
/* 则该事件继续像originalTouches中的监听器分发 */
if (!isSwallowed) ++mutableTouchesIter;
}
}

/* 多点触摸 */
if (allAtOnceListeners && mutableTouches.size() > 0)
{
auto onTouchesEvent = [&](EventListener* l) -> bool { ... };

dispatchEventToListeners(allAtOnceListeners, onTouchesEvent);
if (event->isStopped()) return;
}

updateListeners(event);
}