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
EventInit
whileIOCContainer
finish its initialization GameFlowController
listen & react to all events- While
EventInit
event is receieved- Print
[GameFlow] OnInit
- Fire
EventFinishInit
- Print
- While
EventFinishInit
event is receieved- Print
[GameFlow] OnFinishInit
- Fire
EventLoadingMain
with progress 0 - Start loading the scene
- Print
- While
EventLoadingMain
event is receieved- Print
[GameFlow] OnLoadingMain progress
- Print
- While
EventLoadedScene
event 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
BagUI
throughUIManager
- Fire
EventBagItemDataChange
withID
=1
andCount
=100
- Fire
EventBagItemDataChange
withID
=1
andCount
=200
- Fire
EventBagDeleteItem
withID
=1
- Close
BagUI
throughUIManager
- Fire
EventBagItemDataChange
withID
=1
andCount
=300
- Fire
EventBagDeleteItem
withID
=2
Let's see whether the
BagUI
can receieve the events in6th
&7th
step
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.