本篇在讲什么 cocos2dx内关于事件监听和派发的调度器EventDispatcher相关内容 本篇适合什么 适合初学Cocos2dx的小白 适合想要学习EventDispatcher的新手 本篇需要什么 对Lua语法有简单认知 对C++语法有简单认知 对Cocos2dx有简单认知 Cocos2dx-Lua的开发环境 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 |
★提高阅读体验★ 👉 ♠ 一级标题 👈👉 ♥ 二级标题 👈👉 ♣ 三级标题 👈👉 ♦ 四级标题 👈 |
目录
- ♠ CCEventDispatcher在干什么
- ♠ 事件的监听和派发
- ♥ 监听
- ♣ addEventListenerWithSceneGraphPriority
- ♣ addEventListenerWithFixedPriority
- ♣ addCustomEventListener
- ♥ 取消监听
- ♣ removeEventListener
- ♣ removeEventListenersForType
- ♣ removeEventListenersForTarget
- ♣ removeCustomEventListeners
- ♣ removeAllEventListeners
- ♥ 暂停和恢复
- ♣ pauseEventListenersForTarget
- ♣ resumeEventListenersForTarget
- ♥ 派发
- ♣ dispatchEvent
- ♣ dispatchCustomEvent
- ♠ 事件监听和派发的实现原理
- ♥ 事件监听后发生了什么
- ♥ 派发是如何进行的
- ♠ 用法小例
- ♥ 绑定节点事件
- ♥ 自定义事件
- ♠ 推送
- ♠ 结语
♠ CCEventDispatcher在干什么
观察者模式是我们最常用的设计模式之一,事件系统就是基本的观察者模式用法,举个简单的例子:
1、A店员根据号码派发餐饭,号码是类型,喊号码给饭
2、B顾客会在喊道38号时取餐,B顾客监听38号类型
以上就是一个最简单的事件监听和派发的例子,而EventDispatcher
处理的就是上述事件的注册和监听
♠ 事件的监听和派发
派发器内提供了事件监听、派发以及取消监听的接口,下述内容中我们将简单认识相关接口的功能和使用
♥ 监听
从头文件中我们可以看到一共提供了三种供我们使用的监听注册方式
void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);
void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);
EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);
♣ addEventListenerWithSceneGraphPriority
该方法为某个Node添加指定事件类型的监听,比如:给按钮A添加点击事件
- 参数
listener:
监听事件的类型
node:
监听事件绑定的节点
- 特点
节点销毁、监听销毁
同场景下,渲染越靠前,监听越靠前
点击两个图片交界处,黄色图片注册的事件执行早于红色图片注册的事件
- 常用事件类型
EventListenerTouchOneByOne // 单点事件
EventListenerTouchAllAtOnce // 多点事件
EventListenerMouse // 鼠标
EventListenerKeyboard // 键盘
EventListenerFocus // 聚焦
EventListenerAcceleration // 加速剂(陀螺仪)
♣ addEventListenerWithFixedPriority
为指定事件添加固定优先级的监听
- 参数
listener:
监听事件的类型
fixedPriority:
优先级
- 特点
不绑节点,不会自动销毁,注册后一直存在
设置优先级越低,执行顺序越靠前
- 常用事件类型
EventListenerCustom // 自定义事件
♣ addCustomEventListener
添加自定义事件监听器,用的比较少,一般上边俩方法基本满足需要了
- 参数
eventName:
事件名,字符串
callback:
监听到事件后的执行回调
- 返回值
生成好的事件类型,绑定了事件名和回调
- 特点
不和节点,不会自动销毁,注册后一直存在
固定优先级为1
♥ 取消监听
取消监听有很多种不同的方式,也有根据注册方式存在特定的取消方式
void removeEventListener(EventListener* listener);
void removeEventListenersForType(EventListener::Type listenerType);
void removeEventListenersForTarget(Node* target, bool recursive = false);
void removeCustomEventListeners(const std::string& customEventName);
void removeAllEventListeners();
♣ removeEventListener
根据注册事件时使用的事件类型来取消监听
- 参数
listener:
和注册时使用的事件类型(同一个)
♣ removeEventListenersForType
删除某个类型所有的监听事件
- 参数
listenerType:
和注册时使用的事件类型(同一个)
- 类型枚举
enum class Type
{
TOUCH_ONE_BY_ONE, // 单点触摸
TOUCH_ALL_AT_ONCE, // 多点触摸
KEYBOARD, // 键盘
MOUSE, // 鼠标
ACCELERATION, // 加速剂
FOCUS, // 焦点
CUSTOM // 自定义
};
♣ removeEventListenersForTarget
删除与指定目标相关联的所有侦听器
- 参数
target:
目标节点
recursive:
是否删除子节点的所有侦听器,默认false
♣ removeCustomEventListeners
删除所有具有相同事件名称的自定义监听器
- 参数
customEventName:
自定义的事件名字
♣ removeAllEventListeners
删除所有监听器
♥ 暂停和恢复
我们可以针对某个节点暂停其监听的功能
♣ pauseEventListenersForTarget
暂停与指定目标相关联的所有侦听器
- 参数
target:
目标节点
recursive:
是否暂停子节点的所有侦听器,默认false
♣ resumeEventListenersForTarget
恢复与指定目标相关联的所有侦听器
- 参数
target:
目标节点
recursive:
是否暂停子节点的所有侦听器,默认false
♥ 派发
相较于监听的多样性,事件的派发就显得相当简洁了,提供两个接口以供事件的派发
void dispatchEvent(Event* event);
void dispatchCustomEvent(const std::string &eventName, void *optionalUserData = nullptr);
♣ dispatchEvent
分派事件,根据事件类型
- 参数
event:
事件类型
♣ dispatchCustomEvent
发送带有事件名称的自定义事件和可选的用户数据
- 参数
eventName:
自定义的事件名字_
optionalUserData:
自定义事件类型EventCustom的userData字段,自定义的_
♠ 事件监听和派发的实现原理
我们已经知道了事件是如何监听和派发的,下面我们简单了解一下其具体的实现原理
♥ 事件监听后发生了什么
稍微追一下代码,我们可以发现监听注册后,所有的监听事件根据优先级被存进了两个数组内
std::vector<EventListener*>* _fixedListeners;
std::vector<EventListener*>* _sceneGraphListeners;
♥ 派发是如何进行的
在导演类Director
内可以看到,在实例派发器后,每次绘制都会调用派发器的dispatchEvent
方法,方法内会根据事件类型去寻找监听列表内符合条件的监听执行
♠ 用法小例
因为博主主要用的是cocos2dx+lua,所以这里提供几个lua写的用法小例子
♥ 绑定节点事件
- 为一个Layer注册了一个点击开始事件
-- 执行回调
local func1 = function()
end
-- 绑定节点
local layer = cc.LayerColor:create(cc.c4b(255, 255, 0, 255))
hummer.scene:addChild(layer)
layer:setContentSize(cc.size(100,100))
-- 事件类型
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(func1,cc.Handler.EVENT_TOUCH_BEGAN)
-- 注册监听事件
local eventDispatcher = layer:getEventDispatcher()
layer.cacheEventListener = listener
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
♥ 自定义事件
- 注册一个名为
event_enter_game
的自定义事件
-- 注册
local enterGameFunc = function()
end
local listener = cc.EventListenerCustom:create("event_enter_game", enterGameFunc)
cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(listener, 1)
-- 派发
cc.Director:getInstance():getEventDispatcher():dispatchCustomEvent("event_enter_game")
♠ 推送
- Github
https://github.com/KingSun5
♠ 结语
若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。