Event dispatcher unity c# pattern

How is it going?

WTF?

This script is an implementation of an event dispatcher component in the Unity game engine. The event dispatcher component provides a way for objects in a Unity game to communicate with each other by allowing objects to listen for events, and for other objects to dispatch those events.
The EventDispatcherComponent class implements three main methods: AddEventListener, RemoveEventListener, and DispatchEvent. The AddEventListener method is used to subscribe an object to a specific event, while the RemoveEventListener method is used to unsubscribe an object from that event. The DispatchEvent method is used to trigger an event, which will result in all objects that are subscribed to that event having their event listener function executed.
In this script, there is also a set of methods that specifically handle the “AddDamageToPlayer” event. These methods allow objects to subscribe to or unsubscribe from the “AddDamageToPlayer” event, and for the event to be triggered.
Overall, this event dispatcher component provides a convenient way for objects in a Unity game to communicate with each other in a decoupled manner, where objects do not need to have direct references to each other in order to interact.

ChatGPT

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”.

Leave a Reply

Your email address will not be published. Required fields are marked *