The EventManager for IOCContainer.
You can add package from git url through the Package Manager.
All the following package should be added.
| Package | Description |
|---|---|
| https://github.com/kakashiio/Unity-Reflection.git#1.0.0 | Reflection Library |
| https://github.com/kakashiio/Unity-IOC.git#1.0.0 | IOC Library |
| https://github.com/kakashiio/Unity-IOC-Event.git#1.0.0 | IOC-Event Library |
Imagine we want to implement the following game flow:
- Fire
EventInitwhileIOCContainerfinish its initialization GameFlowControllerlisten & react to all events- While
EventInitevent is receieved- Print
[GameFlow] OnInit - Fire
EventFinishInit
- Print
- While
EventFinishInitevent is receieved- Print
[GameFlow] OnFinishInit - Fire
EventLoadingMainwith progress 0 - Start loading the scene
- Print
- While
EventLoadingMainevent is receieved- Print
[GameFlow] OnLoadingMain progress
- Print
- While
EventLoadedSceneevent is receieved- Print
[GameFlow] OnEnterScene scene=Current Active Scene
- Print
- While
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();Add the code above at the first your application is startup.
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;
}
}[IOCComponent]
class Game : IInstanceLifeCycle
{
[Autowired]
private EventManager _EventManager;
public void BeforePropertiesOrFieldsSet()
{
}
public void AfterPropertiesOrFieldsSet()
{
}
public void AfterAllInstanceInit()
{
_EventManager.FireEvent<EventInit>();
}
}[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}");
}
}[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));
}
}Runing the demo and the following messages will be output in the console:
[GameFlow] OnInit
[GameFlow] OnFinishInit
[GameFlow] OnLoadingMain 0
[GameFlow] OnLoadingMain 100
[GameFlow] OnEnterScene scene=UnityEngine.SceneManagement.Scene
Amazing! Right? The IOCContainer & EventManager help you to register all the methods with Event attribute in the IOCContainer into the EventManager, so that when a EventManager's FireEvent is invoke, the relevant method will be invoked automatically.
This sample is useful for global event,such as network message or game's data message which you want to update all the time even though whether the associate UI is open.
Sometimes you need some local event but not global, such the UI will listen the data's event only when the UI is opened. That is what we want to demonstrate the next sample.
Imagine we want to implement the following game flow:
After the IOCContainer was inited:
- Open
BagUIthroughUIManager - Fire
EventBagItemDataChangewithID=1andCount=100 - Fire
EventBagItemDataChangewithID=1andCount=200 - Fire
EventBagDeleteItemwithID=1 - Close
BagUIthroughUIManager - Fire
EventBagItemDataChangewithID=1andCount=300 - Fire
EventBagDeleteItemwithID=2
Let's see whether the
BagUIcan receieve the events in6th&7thstep
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();Add the code above at the first your application is startup.
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}";
}
}class BagUI
{
[Event]
public void OnBagDataChange(EventBagItemDataChange eventBagItemDataChange)
{
Debug.LogError($"[OnBagDataChange] {eventBagItemDataChange}");
}
[Event]
public void OnEventBagDeleteItem(EventBagDeleteItem eventBagDeleteItem)
{
Debug.LogError($"[OnEventBagDeleteItem] {eventBagDeleteItem}");
}
}[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);
}
}We can each time the Open method is invoked, we will Register the new create ui object to the EventManager, the Unregister method will be invoked if the Close method is invoked. We do not need to register all the events in the ui one by one, just register the ui object into the EventManager and then all the methods with Event attribute in the ui object will be register into the EventManager.
[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));
}
}Runing the demo and the following messages will be output in the console:
[OnBagDataChange] ID=1 Count=100
[OnBagDataChange] ID=1 Count=200
[OnEventBagDeleteItem] ID=1
We can find that after we call _UIManager.Close<BagUI>(), BagUI doesn't react to the last two events, that is what we want.