How is it going?
WTF?
I have a nice pattern for you! I use it to my each projects, really good pattern to must known to everybody! Let’s see what we got
using System;
using System.Collections.Generic;
using UnityEngine;
public class EventDispatcherComponent : MonoBehaviour
{
private Dictionary<string, Action<object>> _eventDictionary = new Dictionary<string, Action<object>>();
private void AddEventListener(string eventName, Action<object> listener)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent += listener;
_eventDictionary[eventName] = thisEvent;
}
else
{
thisEvent += listener;
_eventDictionary.Add(eventName, thisEvent);
}
}
private void RemoveEventListener(string eventName, Action<object> listener)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent -= listener;
if (thisEvent == null)
{
_eventDictionary.Remove(eventName);
}
else
{
_eventDictionary[eventName] = thisEvent;
}
}
}
private void DispatchEvent(string eventName, object payload = null)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent.Invoke(payload);
}
}
}
You can use it with singleton pattern if your project is small.
using System;
using System.Collections.Generic;
using UnityEngine;
public class EventDispatcherComponent : MonoBehaviour
{
private static EventDispatcherComponent instance;
private Dictionary<string, Action<object>> _eventDictionary = new Dictionary<string, Action<object>>();
public static EventDispatcherComponent Instance()
{
if (instance == null)
instance = new EventDispatcherComponent();
return instance;
}
private void AddEventListener(string eventName, Action<object> listener)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent += listener;
_eventDictionary[eventName] = thisEvent;
}
else
{
thisEvent += listener;
_eventDictionary.Add(eventName, thisEvent);
}
}
private void RemoveEventListener(string eventName, Action<object> listener)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent -= listener;
if (thisEvent == null)
{
_eventDictionary.Remove(eventName);
}
else
{
_eventDictionary[eventName] = thisEvent;
}
}
}
private void DispatchEvent(string eventName, object payload = null)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent.Invoke(payload);
}
}
}
If you have a big cock project, you really don’t need to use this guide, because you are good and already know everythimg what you want! However, you have a big project with many systems, use it with Dependency injection and highlight abstraction levels and systems in your application, create a few EventDispatcher’s to separate many events to groups and put it to different scripts and calling it.
using System;
using System.Collections.Generic;
using UnityEngine;
public class EventDispatcherComponent : MonoBehaviour
{
private Dictionary<string, Action<object>> _eventDictionary = new Dictionary<string, Action<object>>();
private void AddEventListener(string eventName, Action<object> listener)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent += listener;
_eventDictionary[eventName] = thisEvent;
}
else
{
thisEvent += listener;
_eventDictionary.Add(eventName, thisEvent);
}
}
private void RemoveEventListener(string eventName, Action<object> listener)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent -= listener;
if (thisEvent == null)
{
_eventDictionary.Remove(eventName);
}
else
{
_eventDictionary[eventName] = thisEvent;
}
}
}
private void DispatchEvent(string eventName, object payload = null)
{
if (_eventDictionary.TryGetValue(eventName, out Action<object> thisEvent))
{
thisEvent.Invoke(payload);
}
}
#region addDamageToPlayer
public void AddDamageToPlayerActionAdd(Action<object> listener)
{
AddEventListener("AddDamageToPlayer", listener);
}
public void AddDamageToPlayerActionRemove( Action<object> listener)
{
RemoveEventListener("AddDamageToPlayer", listener);
}
public void AddDamageToPlayerActionDispatch()
{
DispatchEvent("AddDamageToPlayer");
}
#endregion
}
region addDamageToPlayer this is to easily call function what i need to use and i don’t need remember that name or create enum class for string eventName. Just create a public method and call it whatever you want.
How to use event dispatcher in another classes example
PlayerComponent
using UnityEngine;
public class PlayerComponent : MonoBehaviour
{
[SerializeField] private float moveSpeed;
[SerializeField] private float jumpSpeed;
private EventDispatcherComponent eventDispatcher;
public void Setup(EventDispatcherComponent eventDispatcherComponent)
{
this.eventDispatcher = eventDispatcherComponent;
}
...
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.tag.Equals("Enemy"))
{
AddDamage();
}
}
//call Action to damage player
private void AddDamage()
{
eventDispatcher.AddDamageToPlayerActionDispatch();
}
HealthComponent
using System;
using System.Collections;
using UnityEngine;
public class HealthComponent : MonoBehaviour
{
[SerializeField] private GameObject[] hpPrefabs;
[SerializeField] private int hp=4;
[SerializeField] private float invulnerableTime=1;
[SerializeField] private EventDispatcherComponent eventDispatcher;
private bool isInvulnerable;
private Action<object> onAddDamageToPlayerAction;
//subscribe to Actions
private void Start()
{
eventDispatcher.AddDamageToPlayerActionAdd(RemoveHealth);
}
//if this GameObject was destroyed, we need to unsubscribe really
private void OnDestroy()
{
eventDispatcher.AddDamageToPlayerActionRemove(RemoveHealth);
}
private void RemoveHealth(object o)
{
if (hp <= 0) return;
if (!isInvulnerable)
{
StartCoroutine(Invulnerable());
for (int i = 3; i < hpPrefabs.Length; i--)
{
if (hpPrefabs[i].activeSelf)
{
hpPrefabs[i].SetActive(false);
hp -= 1;
break;
}
}
}
}
}
private void RemoveHealth(object o) and object payload = null – this is for send more details/informations. You can use it to send “int id” or “string”.