Events are not about reducing dependencies. The number of dependencies you need without events is the same as with events. The only exception might be a class that acts as a mediator, but even this class may or may not use events. So, the amount of dependencies you have remains unchanged just because you’re using events. Instead, events are about inverting dependencies and providing a notification when something happens.
There are three key topics to address here: events, events with Scriptable Objects (SO), and Ryan’s video.
First, about events:
Take the example of OnPlayerDeath without using an SO. You need something to happen when the player dies, let’s say the screen flashes. Instead of writing code inside the player class that directly depends on a ScreenFlash class and calls its flash method, you invert the dependency. The ScreenFlash class subscribes to the OnPlayerDeath event, so it listens for when the player dies.
This inversion is beneficial because now the UI class, ScreenFlash, depends on the player class, which is less likely to change. The player’s death mechanic is a core part of your game’s logic and is unlikely to be modified frequently, whereas the visual effect of the screen flash could change more often.
For instance, if you later decide to add a sound effect when the player dies, you can create a new class that subscribes to the same OnPlayerDeath event and plays the sound. If you then replace the screen flash with a death counter, you can simply swap out the ScreenFlash class or keep both without altering the player class at all.
Without using events, you would have to modify the player class each time, risking introducing bugs or breaking unrelated functionality. Events allow your code to mirror the requirements more cleanly: when you need a new feature (e.g., a counter), you add a corresponding class; when you want to remove a feature (e.g., screen flash), you simply remove the related class, without touching the player script.
You could achieve something similar by having UI classes poll the player’s state every few seconds (e.g., checking Player.IsDead), but polling is less efficient than event-driven code.
Second, events with Scriptable Objects (SO):
As sisus_co explained, you can use a Scriptable Object as a wrapper for events. Since SOs are assets, they can be accessed from anywhere by dragging them into a field in the Unity editor, which makes them convenient for event management.
Third, Ryan’s video:
In my experience, people often overlook the most important point Ryan makes at the start of his video: he and his team are programmers who need to hand off projects to game designers and then move on to the next project. In this context, the SO architecture Ryan presents works well because it allows game designers to make changes without interfering with the programmers’ code or needing the programmers to come back for small adjustments.
However, in teams where programmers are available throughout the project or for solo developers, I’ve found that this SO architecture can introduce unnecessary complexity and make the project overly reliant on that structure. it may not be the best fit for those scenarios.
Lastly, on mixing Actions and events:
Actions and events are not different or directly comparable things. Events are essentially a wrapper around delegates/Actions. The reason to use events is that they only allow other classes to subscribe or unsubscribe to a delegate, preventing accidental modifications like clearing all subscriptions. You can think of events as similar to properties in C#: just as properties encapsulate fields, events encapsulate delegates. Properties control getting and setting values, while events control subscribing and unsubscribing to a delegate.