Search Unity

ScriptableObject Game Events versus Unity Events

Discussion in 'Scripting' started by RogueStargun, Dec 31, 2020.

  1. RogueStargun

    RogueStargun

    Joined:
    Aug 5, 2018
    Posts:
    296
    I've been building a pretty complex VR starfighter type game where you have a cockpit with various controls that basically work using UnityEvents. For example, moving the joystick left and right triggers the VR joystick's OnMoveX UnityEvent which triggers the ship (which is a separate prefab from the cockpit; I used camera stacking -- the cockpit never moves).

    I ran into this article about using scriptable objects for events instead:
    https://unity.com/how-to/architect-...jects#code-example-gameevent-scriptableobject

    I'm starting to realize that coupling the cockpit events with hard references to the ship's monobehaviors where essentially I have one gigantic prefab hierarchy since the ship and the cockpit prefab need to be "together" essentially since they contain so many references to each other.

    I'm wondering whether it makes sense to refactor my gigantic prefab with scriptable object style game events instead. This would involve overhauling every usage of Unity Events in the game. Has anyone tried using a scriptable object event system? Are there other pros other than decoupling prefabs from each other?
     
  2. templewulf

    templewulf

    Joined:
    Dec 29, 2013
    Posts:
    52
    It's similar to the publisher-subscriber pattern implemented with "channels" or "topics".

    Most of the benefits are related to the decoupling you mentioned:
    • Allows a many-to-many relationship, by using channels like associative tables. This helps if you have multiple publishers who might all equally raise the same event.
    • The decoupling means you don't have to inject dependencies with a "game manager" type class every time you load a scene. E.g., your HUD subscribes to PlayerHealthChanged by grabbing the asset from the inspector, and any Player prefab you load in can instantly change the HUD.
    • This decoupling also makes it much easier to send events between objects that might exist in separate scenes, like players, game managers, HUD, level props, etc.
    Some of the drawbacks:
    • Requires defining a new ScriptableObject event type for every event parameter you might want to call. You can set up the event base class to make this super easy, but you can't just write it up on the fly like you can with plain UnityEvent<T> generics.
    • Similarly, you end up with a huge list of global events in your Project view. It's not quite the taboo that global variables are, but it can be quite unwieldy if you use events for everything like the Godot signals model.
    • Since it decouples the subscriber from the publisher, it might be harder to tell who is raising the event. Do we even want it to be *possible* for multiple players to publish to the PlayerHealthChanged event?
    Overall, the advantages outweight the drawbacks. It can do everything plain UnityEvents can do and then some. It's great for situations in which dragging and dropping UnityEvent references in the inspector is otherwise hard to arrange. And it's easy to use those UnityEvents for something if you determine it doesn't warrant a ScriptableObjectEvent. You just have to judge how much (if any) of the infrastructure work your project actually requires.

    It might help to look at some implementations like these:
     
    BonitaPersona likes this.
  3. RogueStargun

    RogueStargun

    Joined:
    Aug 5, 2018
    Posts:
    296
    I actually went forward with a total refactoring of all the events in the game to use this pattern, and I must say it's extremely useful. It's much easier to have RadarTracked enemies pass data to an OnMoveAction subscribed to by the radar display. It makes it easier to have multiple radar displays in the game. Likewise, vfx tends to be easier to implement.
     
    Verne33 and templewulf like this.