H33中的消息机制的使用和原理
目前消息触发分为三类:
- object接口,使用objs_call触发,监听游戏中所有object的消息触发。
- 典型的观察者模式,需要手动注册到某个unit中。所有的object都可以通过这种方式监听任何一个unit上的消息。
- action接口,自动监听所属unit的IID消息,回调信息在action enter时开始生效。
后两种都将消息函数信息存放在unity.ActionManager中,并都使用actions_call回调。
消息机制 | 监听范围 | 触发方式 | 监听信息存放位置 | 添加接口方式 | 自动注册 | 可使用对象 | 可配置监听次数 |
---|---|---|---|---|---|---|---|
object接口 | 全局游戏 | objs_call() | objMgr | add_interface | 是 | object | 不可以 |
观察者模式 | 某个unit | actions_call(unit) | actionMgr | add_observer_interface | 否 | object | 可以 |
action接口 | 所属unit | actions_call(unit) | actionMgr | add_action_interfaces | 是 | action | 不可以 |
先说使用上的区别:
消息机制 | 监听范围 | 触发方式 | 监听信息存放位置 | 添加接口方式 | 自动注册 | 可使用对象 | 可配置监听次数 |
---|---|---|---|---|---|---|---|
object接口 | 全局游戏 | objs_call() | objMgr | add_interface | 是 | object | 不可以 |
观察者模式 | 某个unit | actions_call(unit) | actionMgr | add_observer_interface | 否 | object | 可以 |
action接口 | 所属unit | actions_call(unit) | actionMgr | add_action_interfaces | 是 | action | 不可以 |
1 消息机制的概括介绍
以上三种消息机制,他们的实现都可以分为四个步骤:接口声明,接口注册,监听信息保存以及消息触发。
接口声明在ClientEventInterface中,声明有那些接口以及每个接口有哪些消息处理函数。三种消息机制共用一套消息声明。
接口注册是将object或action添加的接口IID以及实现的接口函数,保存到class中。在这里可以根据IID和funcID找到具体要调用的方法。
监听信息保存是将对监听信息保存到unit中的actionManager中或者全局的objMgr中,在这里可以通过消息的IID找到监听这个消息的所有object或action。
消息触发是根据IID查找监听IID的unit,以及根据funcID去class中的接口信息中找到要调用的函数。
2 使用方法
2.1 添加消息处理函数以及接口类
在ClientEventInterface中预先声明消息,消息处理函数和接口类如下所示
class IOnFuryButtonClick:#一个接口类可以存在多个消息处理函数
def on_fury_button_click(self, stateID):
pass
FURY_BUTTON_CLICK = mgr.createIID(IOnFuryButtonClick)
本文称IOnFuryButtonClick为接口类,它可能包含几个接口(消息处理函数),接口类代表着一类消息集合;本文称函数on_fury_button_click为消息处理函数,它代表着一个消息。如果要监听消息,必须监听接口类中的所有消息
2.2 object接口的注册和使用
接口注册和监听信息保存
在某个object中重写函数init_interfaces
,使用add_interface
添加接口的IID,这个object需要实现接口类中的所有消息处理函数。
def init_interfaces(self):
if super(FuryAction, self).init_interfaces():
self.add_interface(G.IID.FURY_BUTTON_CLICK)
return True
return False
object在创建时,自动将监听信息保存到ObjectManager中。
消息调用
使用以下代码,则所有实现了该接口的object中的函数on_fury_button_click
都会被调用。
G.IID.IOnFuryButtonClick.on_fury_button_click.objs_call(self.furyStateID)
2.3 观察者模式的注册和使用
register_observer可以将object A注册为objectB的某一消息的观察者,当触发objectB的消息时,会调用A中的消息处理函数。
接口注册和监听信息保存
接口注册,重写函数init_observer_interfaces
并使用add_observer_interface
添加接口IID。
def init_observer_interfaces(self):
if super(CompUnitManagerAction, self).init_observer_interfaces():
self.add_observer_interface(G.IID.DEAD)
return True
return False
监听信息保存,通过unitA.actionManager.register_observer(G.IID.DEAD,unit_observer,repeatTimes)
保存监听信息到actionManager中,将unit_observer作为unitA的观察者,观察unit的IID消息。
消息调用
当消息发生时使用代码G.IID.IDeadHandle.on_dead.actions_call(unitA)
即可通知观察unitA的所有观察者,并调用观察者的on_dead消息处理函数。
2.4 action接口注册和监听
action接口的注册只能在action中使用。
接口注册和监听信息保存
接口注册,在action中,重写init_action_interfaces()
函数使用add_action_interface
注册接口类,action注册接口类需要同时实现接口所拥有的所有消息处理函数。
def init_action_interfaces(self):
if super(FireEffectAction, self).init_action_interfaces():
self.add_action_interface(G.IID.ISKILL_APPLY)
return True
return False
监听信息保存(此步为自动),当action在enter时,会将action注册到actionManager里面,同时开始监听接口相关的消息。
消息调用
当消息发生,调用G.IID.ISkillApply.on_apply_skill.actions_call(unitA, self.skillID)
就会调用unitA中实现了ISKILL_APPLY接口的action中的on_apply_skill函数。
注意,actions_call(unitA)同时触发观察者模式的消息回调和action的接口,首先调用观察unitA的观察者,然后调用unitA中action实现的接口。
3 此模块所依赖的模块
此模块将消息处理接口信息注册到ActionManager和ObjectManager中,只依赖这两个模块的实现。
4 代码原理
下文介绍代码的具体原理,只要记住消息机制分为四个步骤:接口声明,接口注册,监听信息保存以及消息触发,那么就比较容易理解。
4.1 消息声明
声明了接口,在三种机制中都可以使用。
在ClientEventInterface中,预先定义所有的消息处理函数,并将这些处理函数分类,将同一类的消息处理函数作为一个接口类。
interfaceManager给每个接口类分配一个IID,并将接口类及消息处理函数相关信息存放在InterfaceManager中。
在InterfaceManager中根据接口类IID就能获得这个接口类所有的消息处理函数信息。
将每个接口类的接口函数改为指向一个ObjectInterfaceFunctor对象,此对象保存iid信息,消息处理函数ID信息,封装消息函数查找过程等,actions_call
和objs_call
都属于该对象。
4.2 object接口
object的创建时首先进行接口注册,init_interface调用add_interface根据添加的接口IID,获得接口所有的消息处理函数名,然后根据函数名找到object的对应函数,存放在object.interfaces中,interfaces={iid:{fid:func},...}
object创建同时要注册到ObjectManager中,此时保存监听消息到ObjectManager.actionMap中。
在objs_call中,首先根据IID在ObjectManager中找到监听IID消息的object,然后根据funcId在object.__class__.interfaces
中找到对应的函数,然后调用。
4.3 观察者模式
使用object.add_observer_interface(iid)
为object进行接口注册,此时将object实现的所有的消息处理函数信息存放在object.__class__observerInterfaces[iid]
中,其中函数信息格式为{funcid:func,..}。
使用ActionManager.register_observer(iid,observer,repeatTimes)
,actionManager.__observers
保存监听iid消息的observer的oid。
当actions_call
消息触发时,actionManager去查找监听此消息的观察者,根据消息的funid调用观察者的消息处理函数。
4.4 action接口
使用action.add_action_interface(iid)
为action进行接口注册,此时将action实现的所有的消息处理函数信息存放在action.__class__.actionInterfaces[iid]
中。
在action enter的时候,自动调用actionManager.register_action(action)
,这时actionManager.__activeActionInterfaceMap
保存监听iid消息的action。
当actions_call
消息触发时,actionManager去查找监听此消息的所有action,根据消息的funid调用action的消息处理函数。