In this lesson, you will learn how to use the Observer Pattern to let your game systems communicate without being tightly bound to one another.
The Problem: Tight Coupling
When you build a game, it is tempting to have your Player script hold a direct reference to your UIManager or AudioManager. For example, your Player might call uiManager.UpdateHealth(10). While simple, this creates "tight coupling." If you ever remove the UI or replace it with a different system, your Player script breaks because it’s looking for something that no longer exists.
The Solution: The Observer Pattern
The Observer pattern acts like a radio broadcast. Instead of the Player hunting down the UIManager, the Player simply broadcasts an "I took damage!" message into the void. Any system that cares about that message—like the UIManager or a SoundManager—subscribes to that broadcast and reacts accordingly. The Player doesn't even need to know these other systems exist!
In Unity, we typically implement this using C# actions (delegates).
using System;
using UnityEngine;
public class Player : MonoBehaviour
{
// The "Broadcast"
public static event Action<int> OnPlayerDamaged;
public void TakeDamage(int amount)
{
// Trigger the event
OnPlayerDamaged?.Invoke(amount);
}
}
Now, your UIManager just needs to "listen":
public class UIManager : MonoBehaviour
{
private void OnEnable() => Player.OnPlayerDamaged += UpdateHealthUI;
private void OnDisable() => Player.OnPlayerDamaged -= UpdateHealthUI;
private void UpdateHealthUI(int damage)
{
// Update the bar here
}
}
Why This Matters
By using this pattern, your Player object remains "pure." It doesn't care how health is displayed or if a sound plays when damage is taken; it only cares about its own logic. This makes your project modular and significantly easier to debug, as you can add or remove systems without ever modifying your Player script.
Key Takeaway: The Observer pattern allows objects to communicate by broadcasting events, ensuring that individual systems remain independent and modular.