In this lesson, you will learn how to use ScriptableObject assets as communication "hubs" to allow disconnected game systems to talk to each other without needing direct references.
The Problem with Direct References
Usually, when one object needs to trigger an action in another, you might use GetComponent or drag a reference into the Inspector. This creates "tight coupling." If your Player needs to tell your UI to update health, the Player now needs to know exactly which UI script exists in the scene. If you delete the UI, your code breaks.
The ScriptableObject Solution
An event-based architecture decouples these systems. Instead of the Player talking to the UI, the Player broadcasts to a "Channel"—a ScriptableObject acting as a neutral intermediary.
- Create the Event Channel: You define a
ScriptableObjectthat holds a C#Action(orUnityEvent). - The Broadcaster: The Player script references this
ScriptableObjectand calls its "Raise" method. - The Listener: The UI script also references the same
ScriptableObjectand "Subscribes" to the event.
Here is how a simple Event Channel looks:
using UnityEngine;
using System;
[CreateAssetMenu]
public class GameEvent : ScriptableObject {
public event Action OnEventRaised;
public void Raise() {
OnEventRaised?.Invoke();
}
}
How it Works in Practice
Because the GameEvent is a file in your Project window (an asset), you can drag this same file into both the Player's Inspector and the UI's Inspector. The Player doesn't care who is listening, and the UI doesn't care who is sending the message. They only care about the channel they share.
This keeps your prefabs modular. You can drop your Player prefab into any scene, and as long as you connect it to the GameEvent asset, the communication system will work instantly without any complex scene-specific setup.
Key Takeaway: ScriptableObject events decouple your systems by creating a shared, asset-based bridge that eliminates the need for direct dependencies between game objects.