Harness Scriptable Objects for Flexible Event Handling in Unity

Harness Scriptable Objects for Flexible Event Handling in Unity

As game developers, we often need to manage complex interactions between various game objects. These interactions can quickly become overwhelming, especially when different systems rely on each other. A great way to simplify these interactions is by using event-driven architecture—and Unity's Scriptable Objects provide an excellent mechanism for building decoupled, reusable, and maintainable event systems.

In this article, I’ll show you how to create a generic event channel using Scriptable Objects in Unity. This approach will allow you to broadcast events across your game systems with any data type, making your codebase more flexible and scalable.

We begin by creating a generic event channel that can handle any data type. This Scriptable Object will broadcast events to any registered listener, passing along data when needed.

using System.Collections.Generic;
using UnityEngine;

public abstract class EventChannel<T> : ScriptableObject 
{
    readonly HashSet<EventListener<T>> observers = new();

    public void Invoke(T value) 
    {
      foreach (var observer in observers) 
      {
         observer.Raise(value);
      }
    }
        
   public void Register(EventListener<T> observer) => observers.Add(observer);
   public void Deregister(EventListener<T> observer) => observers.Remove(observer);
}        

Next, we’ll build an event listener. This listener will automatically register and unregister with the event channel when the object becomes active or inactive.

using UnityEngine;
using UnityEngine.Events;

public abstract class EventListener<T> : MonoBehaviour 
{
    [SerializeField] EventChannel<T> eventChannel;
    [SerializeField] UnityEvent<T> unityEvent;

    protected void Awake() 
    {
        eventChannel.Register(this);
    }
        
    protected void OnDestroy() 
    {
        eventChannel.Deregister(this);
    }
        
    public void Raise(T value) 
    {
        unityEvent?.Invoke(value);
    }   
}        

Now, we create channels and listeners for specific data types (e.g., int or float) by inheriting from the GenericEventListener. Here are two examples:

IntEventChannel.cs

using UnityEngine;

[CreateAssetMenu(menuName = "Events/IntEventChannel")]
public class IntEventChannel : EventChannel<int> { }        

IntEventListener.cs

public class IntEventListener : EventListener<int> { }        

FloatEventChannel.cs

using UnityEngine;

[CreateAssetMenu(menuName = "Events/FloatEventChannel")]
public class FloatEventChannel : EventChannel<float> { }        

FloatEventListener.cs

public class FloatEventListener : EventListener<float> { }        

We now need a script that will raise events in response to in-game actions, such as key presses or game triggers.

using UnityEngine;

public class EventRaiser : MonoBehaviour
{
    public EventChannel<int> intEventChannel;  

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.I))
        {
            intEventChannel.Invoke(Random.Range(1, 100)); 
        }
    }
}        

You can Create as many different variants as your needs.

Why This Approach Is Great for Game Development

  • Highly Modular: Using a generic system allows for flexible reuse of the event system across your game. You can create event channels for any data type without having to recreate the logic.
  • Clean and Decoupled Code: Game objects don’t need to know about each other’s existence to communicate. You can add new listeners and events without rewriting the core systems.
  • Improved Maintenance: As your game grows, maintaining a clean, event-driven architecture will make it much easier to add features, tweak behaviors, or refactor systems.

Try implementing this pattern in your next project and see how it can enhance your game's structure and development process.


#unity3d #scriptableobject

Ritesh Khokhani

25+ Games Released | 12+ Years Experience | Game Architect | Mobile & Web Games

4 个月

Great article, scriptable object is gem in unity. Whether it's data storage, level design, game architecture, modularity, flexibility, decoupling, scriptable object helps in all.

回复

要查看或添加评论,请登录

Golam Mostofa的更多文章

社区洞察

其他会员也浏览了