In this lesson, you will learn how to replace verbose custom delegate definitions with the built-in System.Action type to standardize your event architecture.
Why Simplify Delegates?
In previous lessons, you implemented the Observer Pattern using custom delegate signatures like public delegate void OnHealthChanged(int currentHealth);. While functional, these declarations add clutter to your codebase. If you have ten different events, you end up with ten different custom types that clutter your namespace.
C# provides the System.Action delegate, which is a pre-defined, generic delegate that can represent any method returning void. By using Action<T>, you can standardize your event signatures without needing to manually define a new delegate type every time you want to broadcast a change.
Implementing Action Delegates
Instead of writing a custom delegate, you can simply declare an Action variable. If you need to pass data, use the generic version, Action<T>.
Here is a clean implementation of a PlayerHealth system using Action:
using System;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
// Standardizes the event without custom delegate declarations
public static event Action<int> OnHealthChanged;
private int _health = 100;
public void TakeDamage(int amount)
{
_health -= amount;
// Broadcasts to all listeners
OnHealthChanged?.Invoke(_health);
}
}
Benefits for Game Architecture
By using Action<T>, your code becomes more readable and consistent. When other developers (or your future self) see an Action<float> or Action<GameObject>, they immediately understand the intent without searching for a custom delegate definition file.
Furthermore, Action works seamlessly with the C# event keyword, preserving the safety benefits of your existing Observer Pattern implementation. It forces encapsulation, ensuring that only the class that owns the event can trigger it, while listeners remain decoupled from the source logic. This approach perfectly complements your previous work with Dependency Injection and Service Locators, keeping your game systems lightweight and modular.
Key Takeaway: Replace custom delegate declarations with System.Action to reduce boilerplate code and enforce a consistent standard for event signatures across your game systems.