In this lesson, you will learn how to use C# delegates to create flexible callback mechanisms that allow systems to communicate without needing direct, hard-coded references to one another.
The Problem: Rigid Dependencies
Imagine a PlayerHealth script that needs to trigger a SoundManager to play a "Low Health" sound and an UIPanel to flash red. If PlayerHealth holds a direct reference to both, it becomes tightly coupled. If you later remove the SoundManager or switch to a different UI system, your code breaks.
The Solution: C# Delegates
A delegate acts as a "method signature blueprint." By using a delegate, an object can essentially say, "I don't know who is listening, but I have a notification for anyone who cares."
Instead of talking to specific scripts, your PlayerHealth script simply invokes a delegate variable. Other systems can then "subscribe" their methods to that delegate.
public class PlayerHealth : MonoBehaviour
{
// Define the blueprint for methods that want to listen
public delegate void HealthChangedAction(float currentHealth);
// An instance of the delegate
public HealthChangedAction OnHealthChanged;
public void TakeDamage(float amount)
{
currentHealth -= amount;
// Trigger the callback if anyone is listening
OnHealthChanged?.Invoke(currentHealth);
}
}
Decoupling the Listeners
Now, your UIPanel can listen to PlayerHealth without PlayerHealth ever knowing the UIPanel exists:
public class UIPanel : MonoBehaviour
{
public PlayerHealth player;
void OnEnable() => player.OnHealthChanged += UpdateHealthBar;
void OnDisable() => player.OnHealthChanged -= UpdateHealthBar;
void UpdateHealthBar(float health)
{
// Update UI logic here
}
}
By using this pattern, you keep your PlayerHealth logic clean and focused solely on health calculations. The UI and Sound systems remain entirely optional components; if they aren't in the scene, the PlayerHealth script continues to function perfectly without throwing null reference errors or requiring complex "if-exists" checks.
Key Takeaway: Delegates allow you to invert the flow of communication, enabling objects to broadcast changes without requiring explicit knowledge of the systems reacting to them.