此类库为IOC
库的拓展,旨在实现一个自动注册事件的事件管理器.不再需要像传统项目中自己手动Register
或Unregister
事件.
添加引用 通过Package Manager添加如下依赖:
示例1:全局事件基础 假设我们希望实现如下游戏流程:
当IOCContainer
初始化完成时,触发EventInit
事件
GameFlowController
监听所有事件并做出响应
当收到EventInit
事件时
打印[GameFlow] OnInit
触发EventFinishInit
事件
当收到EventFinishInit
事件时
打印[GameFlow] OnFinishInit
触发EventLoadingMain
,此时进度为0
进行场景加载
当收到EventLoadingMain
事件时
打印[GameFlow] OnLoadingMain 进度值
当收到EventLoadedScene
事件时
打印[GameFlow] OnEnterScene scene=当前激活的场景
创建一个IOCContainer 1 2 3 4 5 6 7 8 ITypeContainer typeContainer = new TypeContainerCollection(new List<ITypeContainer> { new TypeContainer(Assembly.GetExecutingAssembly()), new TypeContainer(typeof (IOCComponent).Assembly), new TypeContainer(typeof (EventManager).Assembly) }); new IOCContainerBuilder(typeContainer).Build();
将上述代码添加到你应用程序启动的位置.
先定义所需的事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class EventInit : EventArg {}class EventFinishInit : EventArg {}class EventLoadingMain : EventArg { public float Progress; public EventLoadingMain (float progress ) { Progress = progress; } } class EventLoadedScene : EventArg { public Scene Scene; public EventLoadedScene (Scene scene ) { Scene = scene; } }
定义Game
以响应IOCContainer
的生命周期 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [IOCComponent ] class Game : IInstanceLifeCycle { [Autowired ] private EventManager _EventManager; public void BeforePropertiesOrFieldsSet () { } public void AfterPropertiesOrFieldsSet () { } public void AfterAllInstanceInit () { _EventManager.FireEvent<EventInit>(); } }
定义GameFlowController
响应事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 [IOCComponent ] class GameFlowController { [Autowired ] private AssetLoader _AssetLoader; [Autowired ] private EventManager _EventManager; [Event ] public void OnInit (EventInit eventInit ) { Debug.LogError("[GameFlow] OnInit" ); _EventManager.FireEvent<EventFinishInit>(); } [Event ] public void OnFinishInit (EventFinishInit eventFinishInit ) { Debug.LogError("[GameFlow] OnFinishInit" ); _EventManager.FireEvent(new EventLoadingMain(0 )); _AssetLoader.LoadScene("ScenePath" , (scene) => { _EventManager.FireEvent(new EventLoadingMain(100 )); }); } [Event ] public void OnLoadingMain (EventLoadingMain eventLoadingMain ) { Debug.LogError($"[GameFlow] OnLoadingMain {eventLoadingMain.Progress} " ); } [Event ] public void OnEnterScene (EventLoadedScene eventLoadedScene ) { Debug.LogError($"[GameFlow] OnEnterScene scene={eventLoadedScene.Scene} " ); } }
定义AssetLoader
模拟资源加载 1 2 3 4 5 6 7 8 9 10 11 12 13 [IOCComponent ] class AssetLoader { [Autowired ] private EventManager _EventManager; public void LoadScene (string scenePath, Action<Scene> onLoadedScene ) { var scene = SceneManager.GetActiveScene(); onLoadedScene(scene); _EventManager.FireEvent(new EventLoadedScene(scene)); } }
所有工作完成 运行场景会发现控制台中按顺序出现如下输出:
1 2 3 4 5 [GameFlow] OnInit [GameFlow] OnFinishInit [GameFlow] OnLoadingMain 0 [GameFlow] OnLoadingMain 100 [GameFlow] OnEnterScene scene=UnityEngine.SceneManagement.Scene
很神奇,对吧!IOCContainer
和EventManager
帮助你将IOCContainer
中所有带有Event
attribute的方法注册到EventManager
中,因此当调用EventManager
的FireEvent
时,对应的方法将会被自动调用.
该例子适合于类似全局事件注册,比如网络消息注册等,此类消息的特点为只要整个游戏还在运行中,那么这类消息被永久监听,不会从监听中移除.
那么对于类似UI界面的消息需求,有的时候只需要在打开UI时监听,在关闭UI时移除监听.该EventManager
也是支持的.
示例2:局部事件基础 假设我们希望实现如下游戏流程:
当IOCContainer
初始化完成时:
通过UIManager
打开BagUI
触发EventBagItemDataChange
事件,将ID
为1
的物件的Count
更新为100
触发EventBagItemDataChange
事件,将ID
为1
的物件的Count
更新为200
触发EventBagDeleteItem
事件,将ID
为1
的物件移除
通过UIManager
关闭BagUI
触发EventBagItemDataChange
事件,将ID
为1
的物件的Count
更新为300
触发EventBagDeleteItem
事件,将ID
为2
的物件移除
注意观察BagUI
能否收到第6
步和第7
的事件
创建一个IOCContainer 1 2 3 4 5 6 7 8 ITypeContainer typeContainer = new TypeContainerCollection(new List<ITypeContainer> { new TypeContainer(Assembly.GetExecutingAssembly()), new TypeContainer(typeof (IOCComponent).Assembly), new TypeContainer(typeof (EventManager).Assembly) }); new IOCContainerBuilder(typeContainer).Build();
将上述代码添加到你应用程序启动的位置.
定义事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class EventBagItemDataChange : EventArg { public int ID; public int Count; public EventBagItemDataChange (int id, int count ) { ID = id; Count = count; } public override string ToString () { return $"ID={ID} Count={Count} " ; } } class EventBagDeleteItem : EventArg { public int ID; public EventBagDeleteItem (int id ) { ID = id; } public override string ToString () { return $"ID={ID} " ; } }
定义背包BagUI
1 2 3 4 5 6 7 8 9 10 11 12 13 class BagUI { [Event ] public void OnBagDataChange (EventBagItemDataChange eventBagItemDataChange ) { Debug.LogError($"[OnBagDataChange] {eventBagItemDataChange} " ); } [Event ] public void OnEventBagDeleteItem (EventBagDeleteItem eventBagDeleteItem ) { Debug.LogError($"[OnEventBagDeleteItem] {eventBagDeleteItem} " ); } }
该UI为了演示对事件的监听,目前没有任何逻辑,仅仅在收到事件时进行打印.
定义一个用于辅助测试的UIManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 [IOCComponent ] class UIManager { [Autowired ] private EventManager _EventManager; private IIOCContainer _IOCContainer; private Dictionary<Type, object > _UIs = new Dictionary<Type, object >(); public void Open <T >(Action<T> onOpened ) where T : new () { var uiType = typeof (T); if (_UIs.ContainsKey(uiType)) { onOpened((T) _UIs[uiType]); return ; } var t = new T(); _EventManager.Register(t); _UIs.Add(uiType, t); onOpened.Invoke(t); } public void Close <T >() { var uiType = typeof (T); if (!_UIs.ContainsKey(uiType)) { return ; } var ui = _UIs[uiType]; _UIs.Remove(uiType); _EventManager.Unregister(ui); } }
可以看到每次Open
时,我们将创建的UI对象通过Register
方法注册到EventManager
中,而每次Close
时,我们将创建的UI对象注册的所有事件通过Unregister
方法从EventManager
中移除.可以看到不需要自己将BagUI
中的对象一个个地进行注册和反注册.EventManager.Register(object)
方法将object
中所有带有Event
attribute的方法注册到事件管理器中.
定义Game
进行最终测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [IOCComponent ] class Game : IInstanceLifeCycle { [Autowired ] private UIManager _UIManager; [Autowired ] private EventManager _EventManager; public void BeforePropertiesOrFieldsSet () { } public void AfterPropertiesOrFieldsSet () { } public void AfterAllInstanceInit () { _UIManager.Open<BagUI>((ui) => { }); _EventManager.FireEvent(new EventBagItemDataChange(1 , 100 )); _EventManager.FireEvent(new EventBagItemDataChange(1 , 200 )); _EventManager.FireEvent(new EventBagDeleteItem(1 )); _UIManager.Close<BagUI>(); _EventManager.FireEvent(new EventBagItemDataChange(1 , 300 )); _EventManager.FireEvent(new EventBagDeleteItem(2 )); } }
所有工作完成 运行场景会发现控制台中按顺序出现如下输出:
1 2 3 [OnBagDataChange] ID=1 Count=100 [OnBagDataChange] ID=1 Count=200 [OnEventBagDeleteItem] ID=1
可以看到当调用_UIManager.Close<BagUI>()
后,BagUI
没有触发另外两个事件.这正是我们所预期的效果.
工程地址 完整的Package工程地址在https://github.com/kakashiio/Unity-IOC-Event
致谢 感谢百忙之中阅读本文,如果觉得我的文章帮到了你,欢迎:转载、关注git、为仓库增加star等.你的简单回馈将是我继续创作的动力.