H33中的消息機(jī)制的使用和原理
目前消息觸發(fā)分為三類:
- object接口坎吻,使用objs_call觸發(fā)郊愧,監(jiān)聽游戲中所有object的消息觸發(fā)掏呼。
- 典型的觀察者模式帜慢,需要手動注冊到某個unit中笼裳。所有的object都可以通過這種方式監(jiān)聽任何一個unit上的消息唯卖。
- action接口,自動監(jiān)聽所屬unit的IID消息躬柬,回調(diào)信息在action enter時開始生效拜轨。
后兩種都將消息函數(shù)信息存放在unity.ActionManager中,并都使用actions_call回調(diào)允青。
消息機(jī)制 | 監(jiān)聽范圍 | 觸發(fā)方式 | 監(jiān)聽信息存放位置 | 添加接口方式 | 自動注冊 | 可使用對象 | 可配置監(jiān)聽次數(shù) |
---|---|---|---|---|---|---|---|
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 | 不可以 |
先說使用上的區(qū)別:
消息機(jī)制 | 監(jiān)聽范圍 | 觸發(fā)方式 | 監(jiān)聽信息存放位置 | 添加接口方式 | 自動注冊 | 可使用對象 | 可配置監(jiān)聽次數(shù) |
---|---|---|---|---|---|---|---|
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 消息機(jī)制的概括介紹
以上三種消息機(jī)制橄碾,他們的實現(xiàn)都可以分為四個步驟:接口聲明,接口注冊颠锉,監(jiān)聽信息保存以及消息觸發(fā)法牲。
接口聲明在ClientEventInterface中,聲明有那些接口以及每個接口有哪些消息處理函數(shù)琼掠。三種消息機(jī)制共用一套消息聲明拒垃。
接口注冊是將object或action添加的接口IID以及實現(xiàn)的接口函數(shù),保存到class中瓷蛙。在這里可以根據(jù)IID和funcID找到具體要調(diào)用的方法悼瓮。
監(jiān)聽信息保存是將對監(jiān)聽信息保存到unit中的actionManager中或者全局的objMgr中,在這里可以通過消息的IID找到監(jiān)聽這個消息的所有object或action艰猬。
消息觸發(fā)是根據(jù)IID查找監(jiān)聽IID的unit横堡,以及根據(jù)funcID去class中的接口信息中找到要調(diào)用的函數(shù)。
2 使用方法
2.1 添加消息處理函數(shù)以及接口類
在ClientEventInterface中預(yù)先聲明消息冠桃,消息處理函數(shù)和接口類如下所示
class IOnFuryButtonClick:#一個接口類可以存在多個消息處理函數(shù)
def on_fury_button_click(self, stateID):
pass
FURY_BUTTON_CLICK = mgr.createIID(IOnFuryButtonClick)
本文稱IOnFuryButtonClick為接口類命贴,它可能包含幾個接口(消息處理函數(shù)),接口類代表著一類消息集合腊满;本文稱函數(shù)on_fury_button_click為消息處理函數(shù)套么,它代表著一個消息。如果要監(jiān)聽消息碳蛋,必須監(jiān)聽接口類中的所有消息
2.2 object接口的注冊和使用
接口注冊和監(jiān)聽信息保存
在某個object中重寫函數(shù)init_interfaces
,使用add_interface
添加接口的IID胚泌,這個object需要實現(xiàn)接口類中的所有消息處理函數(shù)。
def init_interfaces(self):
if super(FuryAction, self).init_interfaces():
self.add_interface(G.IID.FURY_BUTTON_CLICK)
return True
return False
object在創(chuàng)建時肃弟,自動將監(jiān)聽信息保存到ObjectManager中玷室。
消息調(diào)用
使用以下代碼,則所有實現(xiàn)了該接口的object中的函數(shù)on_fury_button_click
都會被調(diào)用笤受。
G.IID.IOnFuryButtonClick.on_fury_button_click.objs_call(self.furyStateID)
2.3 觀察者模式的注冊和使用
register_observer可以將object A注冊為objectB的某一消息的觀察者穷缤,當(dāng)觸發(fā)objectB的消息時,會調(diào)用A中的消息處理函數(shù)箩兽。
接口注冊和監(jiān)聽信息保存
接口注冊津肛,重寫函數(shù)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
監(jiān)聽信息保存汗贫,通過unitA.actionManager.register_observer(G.IID.DEAD,unit_observer,repeatTimes)
保存監(jiān)聽信息到actionManager中身坐,將unit_observer作為unitA的觀察者秸脱,觀察unit的IID消息。
消息調(diào)用
當(dāng)消息發(fā)生時使用代碼G.IID.IDeadHandle.on_dead.actions_call(unitA)
即可通知觀察unitA的所有觀察者部蛇,并調(diào)用觀察者的on_dead消息處理函數(shù)摊唇。
2.4 action接口注冊和監(jiān)聽
action接口的注冊只能在action中使用。
接口注冊和監(jiān)聽信息保存
接口注冊涯鲁,在action中巷查,重寫init_action_interfaces()
函數(shù)使用add_action_interface
注冊接口類,action注冊接口類需要同時實現(xiàn)接口所擁有的所有消息處理函數(shù)抹腿。
def init_action_interfaces(self):
if super(FireEffectAction, self).init_action_interfaces():
self.add_action_interface(G.IID.ISKILL_APPLY)
return True
return False
監(jiān)聽信息保存(此步為自動)岛请,當(dāng)action在enter時,會將action注冊到actionManager里面幢踏,同時開始監(jiān)聽接口相關(guān)的消息髓需。
消息調(diào)用
當(dāng)消息發(fā)生,調(diào)用G.IID.ISkillApply.on_apply_skill.actions_call(unitA, self.skillID)
就會調(diào)用unitA中實現(xiàn)了ISKILL_APPLY接口的action中的on_apply_skill函數(shù)房蝉。
注意,actions_call(unitA)同時觸發(fā)觀察者模式的消息回調(diào)和action的接口微渠,首先調(diào)用觀察unitA的觀察者搭幻,然后調(diào)用unitA中action實現(xiàn)的接口。
3 此模塊所依賴的模塊
此模塊將消息處理接口信息注冊到ActionManager和ObjectManager中逞盆,只依賴這兩個模塊的實現(xiàn)檀蹋。
4 代碼原理
下文介紹代碼的具體原理,只要記住消息機(jī)制分為四個步驟:接口聲明云芦,接口注冊俯逾,監(jiān)聽信息保存以及消息觸發(fā),那么就比較容易理解舅逸。
4.1 消息聲明
聲明了接口桌肴,在三種機(jī)制中都可以使用。
在ClientEventInterface中琉历,預(yù)先定義所有的消息處理函數(shù)坠七,并將這些處理函數(shù)分類,將同一類的消息處理函數(shù)作為一個接口類旗笔。
interfaceManager給每個接口類分配一個IID彪置,并將接口類及消息處理函數(shù)相關(guān)信息存放在InterfaceManager中。
在InterfaceManager中根據(jù)接口類IID就能獲得這個接口類所有的消息處理函數(shù)信息蝇恶。
將每個接口類的接口函數(shù)改為指向一個ObjectInterfaceFunctor對象拳魁,此對象保存iid信息,消息處理函數(shù)ID信息撮弧,封裝消息函數(shù)查找過程等潘懊,actions_call
和objs_call
都屬于該對象姚糊。
4.2 object接口
object的創(chuàng)建時首先進(jìn)行接口注冊,init_interface調(diào)用add_interface根據(jù)添加的接口IID卦尊,獲得接口所有的消息處理函數(shù)名叛拷,然后根據(jù)函數(shù)名找到object的對應(yīng)函數(shù),存放在object.interfaces中岂却,interfaces={iid:{fid:func},...}
object創(chuàng)建同時要注冊到ObjectManager中忿薇,此時保存監(jiān)聽消息到ObjectManager.actionMap中。
在objs_call中躏哩,首先根據(jù)IID在ObjectManager中找到監(jiān)聽IID消息的object署浩,然后根據(jù)funcId在object.__class__.interfaces
中找到對應(yīng)的函數(shù),然后調(diào)用扫尺。
4.3 觀察者模式
使用object.add_observer_interface(iid)
為object進(jìn)行接口注冊筋栋,此時將object實現(xiàn)的所有的消息處理函數(shù)信息存放在object.__class__observerInterfaces[iid]
中,其中函數(shù)信息格式為{funcid:func,..}正驻。
使用ActionManager.register_observer(iid,observer,repeatTimes)
弊攘,actionManager.__observers
保存監(jiān)聽iid消息的observer的oid。
當(dāng)actions_call
消息觸發(fā)時姑曙,actionManager去查找監(jiān)聽此消息的觀察者襟交,根據(jù)消息的funid調(diào)用觀察者的消息處理函數(shù)。
4.4 action接口
使用action.add_action_interface(iid)
為action進(jìn)行接口注冊伤靠,此時將action實現(xiàn)的所有的消息處理函數(shù)信息存放在action.__class__.actionInterfaces[iid]
中捣域。
在action enter的時候,自動調(diào)用actionManager.register_action(action)
宴合,這時actionManager.__activeActionInterfaceMap
保存監(jiān)聽iid消息的action焕梅。
當(dāng)actions_call
消息觸發(fā)時,actionManager去查找監(jiān)聽此消息的所有action卦洽,根據(jù)消息的funid調(diào)用action的消息處理函數(shù)贞言。