此类库为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等.你的简单回馈将是我继续创作的动力.