玩家在游戏战斗过程中,被某个怪物把血打掉了,然后界面上的UI血条的数值就要发生变化,
按照一般的处理方式,我们在战斗的逻辑里面掉血后,要去找到UI界面中的某个节点,把数值给它设置好。一个查找还好,要是多个地方需要改变数值,多个节点都需要被改变,玩家战斗逻辑,不可能每个节点都去找一下,然后设置一下,这样也不灵活,也不方便扩展。这样就相当于玩家Player对象与要更新显示的这些对象耦合在一起了。所以就需要编写一个模块来解耦,这个模块就是事件订阅与发布模块。针对上面的情况,如何解耦呢?
我们引入一个事件监听与事件触发机制,当我们某个逻辑对某个事件感兴趣的时候,我们就向事件订阅与发布模块发起一个监听,这样事件订阅与发布模块保留了监听者的回掉函数。当玩家在战斗中掉血了以后,只要通过事件与订阅模块,派送一个事件就可以了,事件订阅模块内部,看哪些对这个事件感兴趣,分别回调,这样玩家不用去关心当前多少人对这个事件感兴趣。而对事件感兴趣的监听者也不用关心是谁触发的,这样它们之间就解耦了。
事件订阅与发布模块具体如何设计呢?新建一个单例事件管理组件类EventMgr,这个单例组件实例化到GameApp节点上。如图1.7-2
(图1.7-2)
events_map是一个表,存放了哪些监听者对哪些事件感兴趣。当events_map里面有数据的时候,数据结构如下: { “事件名字1”: [监听者1{caller, func}, 监听者2], “事件名字2”: []}
events_map数据结构中,基于事件名字的key, value是一个数组对象,存放了对这个事件感兴趣的所有的监听者,每个监听者,保存一个caller与func,当事件触发func调用时,func中的this为caller。
接下来我们来看下提供给监听者的监听事件接口如图1.7.3:
(图1..7-3)
当我们要监听某个事件的时候,传入事件的名字,回调时的this对象(caller), 回调函数func。
先判断一下有没有其它的人在监听,eventName这个key是否为null, 如果为null就创建一个数组对象用来保存所有的监听者。然后再push一个监听者对象到数组里面,对应的结构为 {caller: xxxxx, func: xxxxx}。
接下来我们来看下如何派送发布一个事件,如图1.7.4:
(图1..7-4)
当要派送发布一个事件的时候,调用Emit函数,eventName为事件的名字,udata为派送的数据。先判断一下是否有这个事件的监听队列,如果没有,直接返回。遍历事件队列数组里面的每个监听对象,显示的传递caller作为函数的this, 把udata传递给回调函数。这样监听者的事件回调函数就会被调用。
今天的教程分享就到这里,具体代码可以阅读EventMgr.ts,把代码阅读一遍,完整的掌握事件订阅与发布模块的编写与实现。
网友评论