In this lesson, you will learn how to sync your inventory data with your UI display without creating "spaghetti code" dependencies.
The Problem of Tight Coupling
When a beginner first builds an inventory, they often place a reference to the InventoryUI directly inside the Inventory class. This causes issues: if you decide to change your UI or swap it out entirely, you have to rewrite your backend logic. By using the Observer Pattern with ScriptableObject Event Channels, we can make these two systems "talk" without ever knowing the other exists.
Connecting Data to UI
The logic flow works in three parts:
- The Inventory Data: When an item is added or removed, it invokes a
GameEventScriptableObject. - The Event Channel: The Inventory doesn’t care who is listening; it simply "broadcasts" that a change occurred.
- The UI Listener: A
GameEventListenercomponent attached to your UI Prefab waits for that specific event and triggers a refresh of the slots.
Implementation Example
Your Inventory script performs the transaction, then fires the event:
public class Inventory : MonoBehaviour
{
public GameEvent onInventoryChanged; // The ScriptableObject channel
public void AddItem(Item item)
{
// ... Logic to add item to internal list ...
onInventoryChanged.Raise(); // Notify any listeners
}
}
On the UI side, your InventoryUI script simply registers a method to that same event. Because both the Inventory and the InventoryUI hold a reference to the same GameEvent asset, they communicate perfectly without the Inventory needing a variable like public InventoryUI myUI;.
This decoupling is vital for complex projects. You can test your inventory system entirely in the console without a UI, or swap your UI Prefab for a completely different design, all without touching a single line of code in your core inventory logic.
Key Takeaway: By using ScriptableObject Event Channels as a middleman, your UI and Inventory logic remain independent, making your code cleaner, easier to test, and ready for future changes.