Course contentsShow
← Unity Game Development
Lesson 89 of 8282. Scripting and LifecycleFree lesson

Decoupling Systems Using C# Actions and Delegates

Implement an event-driven architecture to notify multiple objects of state changes without requiring them to hold direct references to each other.

Decoupling Systems Using C# Actions and Delegates

In this lesson, you will learn how to notify multiple game systems of state changes using an event-driven architecture, effectively cutting the "cables" between your scripts.

The Problem with Direct References

Up until now, if your Player script wanted to tell the UIManager to update the health bar, you likely used a direct reference (e.g., public UIManager ui;). This creates a tight dependency; if you remove the UIManager, your Player script breaks. As your project grows, these dependencies become a tangled web that is difficult to debug.

The Solution: C# Actions

Instead of the Player knowing who is listening, it simply "shouts" into the void: "Health changed!" Any object interested in that shout (like the UIManager or a SoundManager) can subscribe to it. We use the System.Action delegate to represent this notification.

Here is how you implement it:

1. The Publisher (Player.cs)

using System;
using UnityEngine;

public class Player : MonoBehaviour
{
    // Define the event
    public static event Action OnHealthChanged;

    public void TakeDamage()
    {
        // Trigger the event
        OnHealthChanged?.Invoke();
    }
}

2. The Subscriber (UIManager.cs)

using UnityEngine;

public class UIManager : MonoBehaviour
{
    private void OnEnable() => Player.OnHealthChanged += UpdateUI;
    private void OnDisable() => Player.OnHealthChanged -= UpdateUI;

    private void UpdateUI()
    {
        Debug.Log("UI Updated: Health bar redrawn.");
    }
}

Why This Works

The Player script has zero knowledge of the UIManager. It doesn't care if one, ten, or zero scripts are listening. This is "decoupling." You can add a SoundManager or a VFXController later, and you won't have to change a single line of code in your Player script.

By using OnEnable and OnDisable to subscribe and unsubscribe, you ensure that your code remains memory-safe and that you aren't trying to send events to objects that no longer exist in the scene.

Key Takeaway: Use C# Actions to let objects broadcast messages without needing to know which other scripts are listening, keeping your codebase clean and modular.