Posted February 02, 2024 by ginocarlo01
#ObserverPattern #Unity
In this post, I will explain how I applied the Observer Pattern in my Unity 2D Platformer Project.
What is the observer pattern? Let's suppose we have a collectible, and every time our player collides with that collectible, we want to update our UI. We could explicitly mention the UI in our code, like this:
Alternatively, we could use another design pattern, the singleton:
It may sound like a good idea to always use the singleton, but as the game gets bigger, the use of the observer pattern turns out to be the best option.
The idea here is that every time our player collides with the collectible, we are going to invoke an action. In this way, we don't need to specify which objects we want to notify when we execute this function. But how can they know then?
In general, there should be two things: the subject and the observer. In this case, our Collectable Manager class is the observer (that's why it's listening to the function UpdateCollectableQty), and our subject is the collision. When that subject is called, our listeners will take a specific action that the subject does not have control of.
Ok, but what's the advantage? Imagine that when the collision happened, we had to these things:
In the singleton pattern, I would have to tell specifically which objects and which function I should call. For example:
So, the control stays all in our subject. That's not good practice! It should stay in our observer: collectedAction?.Invoke() That's it! And then all the different behavior will be controlled in the listeners.
Note: The action also sends a parameter, and the function attached to it must have the same parameters; otherwise, it won't work.
This solution made the project much better. Here are a few advantages:
Final example:
private void OnTriggerEnter2D(Collider2D collision)
{
EnterLevelUI.instance.SetLevelText("Level " + (levelIndex + 1)); // We have to tell the class and the function
playerEnteredDoor?.Invoke(levelIndex + 1); // We only tell the action; the function and the class are controlled independently
}
private void OnTriggerExit2D(Collider2D collision)
{
EnterLevelUI.instance.SetLevelText("");
playerEnteredDoor?.Invoke(-1);
}