Course contentsShow
← Unity Game Development
Lesson 458 of 8287. Advanced Game ArchitectureFree lesson

Passing Game Data Through Event Arguments

Design custom event arguments to pass specific game state data safely and efficiently between disparate game components.

In this lesson, you will learn how to transition from simple notifications to data-rich communication by embedding specific game state information directly into your event signatures using custom EventArgs.

Moving Beyond Simple Notifications

While basic events (like an Action or Action<int>) notify listeners that something happened, they often lack the context needed to react intelligently. When your game grows, passing a single primitive type often forces the listener to reach back into your systems to "ask" for data, which re-introduces the coupling you worked so hard to avoid via the Observer pattern.

Instead, we use custom EventArgs to bundle relevant data into a single package sent at the exact moment of the event.

Implementing Custom Event Arguments

To do this, create a class that inherits from System.EventArgs. By defining properties here, you ensure type safety and allow the event sender to remain completely agnostic of who—or what—is listening.

public class PlayerHealthEventArgs : System.EventArgs
{
    public float CurrentHealth { get; }
    public float MaxHealth { get; }

    public PlayerHealthEventArgs(float current, float max)
    {
        CurrentHealth = current;
        MaxHealth = max;
    }
}

Now, define your event using the EventHandler<T> delegate. This standard C# pattern provides a consistent signature (object sender, T e) that makes your architecture predictable and clean:

public class HealthManager : MonoBehaviour
{
    // The event uses our custom class
    public event EventHandler<PlayerHealthEventArgs> OnHealthChanged;

    public void TakeDamage(float amount)
    {
        currentHealth -= amount;
        
        // Bundle the data and fire the event
        OnHealthChanged?.Invoke(this, new PlayerHealthEventArgs(currentHealth, maxHealth));
    }
}

Why This Matters

By using custom event arguments, the listener doesn't need a direct reference to the HealthManager. It simply receives a data packet that contains everything it needs to update a UI bar or trigger a death animation. This approach keeps your components lean, prevents hidden dependencies, and makes your code significantly easier to refactor, as the data contract is explicitly defined in your EventArgs class rather than implicitly assumed by the listeners.

Key Takeaway: Use custom EventArgs to bundle related game state into a single, immutable data packet, ensuring your event-driven systems remain decoupled, type-safe, and highly performant.