事件系统,往小处说它是应用程序内部各个模块交互的设计模式,往大处说它是软件架构的组成模块。Cocos2d-x 3.x之后,引入了新的响应用户事件的机制。事件分发不仅分发系统事件,还可以分发者自定义事件,而且处理顺序的优先级可以根据元素的绘制顺序,大大提高了触摸等事件的管理效率。
教学视频
课程笔记
事件的机制
大多数事件系统是订阅者设计模式。
事件是用于处理模块之间通信的模型。比如模块A出发某个事件的时候,调用模块B的方法。如果模块A直接调用B的方法,那么需要在模块A对B进行实例化,那么如果B发生变化,A可能也需要发生变化。而且有可能B和A是完全独立的系统,或者A无法提前知道B的情况,甚至可能开始的时候并没有B的存在。
那么订阅者模块就是将事件的触发者和响应者分开。流程是,模块B向事件分发器注册了一个订阅者listenb,表明自己需要处理类型typeA的事件消息,listenb带一个处理事件的回调方法地址func;模块A在事件发生的时候向事件分发器发出类型typeA的事件消息同志,并传入参数args;事件分发器接到消息后,从订阅者列表找到订阅者listenb,并相应该事件触发listenb的回调韩述func,并传入args。
这样,事件可以不依赖响应者的实现,而预先定义,事件响应者甚至可以动态的修改删除。甚至一个事件类型没有任何订阅者都没有关系,该事件将什么都不发生。
事件系统有许多优点:
1、减少软件内模块之间的内聚,且保持模块之间的高效通信;
2、使得系统可以提前预定义一些事件(比如触摸、加速计等系统事件);
3、解除了模块之间的耦合,使得模块之间更加独立;
4、一个事件可以对应多个订阅者(多个订阅者都是订阅一个类型的事件),多个订阅者可以对应一个事件源(多个不同类型的订阅者,一个事件源可能引起多个类型的事件,比如物理碰撞发生时,物理引擎需要计算碰撞后的位置,AI系统需要做数值计算,动画特效系统可能播放一些动画特效。)
事件系统也有限制:
1、事件系统影响系统,因为在搜索订阅者的时候需要排序查询,比如AI算法在每帧需要实时更新多个角色的游戏状态,不适合用事件分发。
2、订阅者虽然有回调函数,但是永远不如直接调用好用。
事件的订阅者
订阅者是EventListener的子类,比如EventListenerTouchOneByOne是用来相应触摸事件的。每个EventListener由一个或者多个回调函数、一个订阅者Type、一个listenerID组成,Type是用来区分EventListener的,listenerID与Type一一对应(除了Type为CUSTOM的时候,listenerID数量无限);listenerID又与事件的Type 对应,事件分发器得到事件Type的时候,也就得到listenerID,进而找到事件订阅者。事件包含事件类型和参数,类型与listenerID一一对应(触摸事件对应2个事件订阅器EventListenerTouchOneByOne和EventListenerTouchAllAtOnce,CUSTOM事件的参数eventName为listenerID。)
注册订阅者,通过addEventListenerWithSceneGraphPriority和addEventListenerWithFixedPriority。addEventListenerWithSceneGraphPriority第二个参数为Node,优先级为0,顺序按照node绘制顺序的反序;addEventListenerWithFixedPriority第二个参数为int,不能设置为0,数字越小优先级越高。无法判断订阅者的关联的node,当优先级通过第二个函数设置时,可以通过setPriority修改优先级。
删除订阅者,通过removeEventListener、removeCustomEventListeners、removeAllEventListeners、removeEventListenersForTarget、removeEventListenersForType。注意所有的EventCustomListener的Type都是CUSTOM。
修改订阅者,调用Node的onExit的时候会暂停订阅者pauseEventListenersForTarget,调用OnEnter会恢复订阅者resumeEventListenersForTarget。修改非Node的订阅者需要调用订阅者的setEnabled方法。