Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Scriptable Object Event System on Huge Project

Discussion in 'Scripting' started by Luxgile, Feb 4, 2019.

  1. Luxgile

    Luxgile

    Joined:
    Nov 27, 2016
    Posts:
    16
    I've been working with Unity for some years now and i've started a project that it's actually growing bigger and bigger. So, before the project ends up being a complete mess i've looking for good design and best ways to avoid bad practices, this led me to Scriptable Objects and the Event System you can create with them:
    https://unity3d.com/es/how-to/architect-with-scriptable-objects

    It actually looks really good and can help with a lot of problems, but i'm actually worried about code traceability and the possible case where you don't know what is calling what and end up in a mess of callbacks.

    Actually this question it's not only about scriptable objects but the usage of events (C# and/or UnityEvents). I would like to know what actually the best aproach for this or if it's not, what should i aim for.
     
    Shorely likes this.
  2. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    389
    This way of using ScriptableObjects, or using events, is about configuring the behaviour of the game instead of coding it.

    You are right about the fact that it will break code traceability, but it's the price to pay in order to have configuration capabilities instead of hard-coding everything.
    If your project grows very large, hard-coding everything will eventually become very messy, and it will be risky to modify some old behaviours. That's where configuration is really important, it makes it less risky (and a lot easier) to modify behaviours.

    I have about the same problem with code traceability, but I have made the choice of using extensively ScriptableObjects and events.
    Doing that means that you will have to change the way you're debugging, but in the end it will help.

    For example, I have a 'Context' system, the game is always in a 'Context', and each 'Action' can be done only in a specific set of 'Contexts'.
    In order to help me debug that, I can enable/disable the 'Context' logging which will log when there's a context change, and display the current context on-screen.
    I also have a debug console which includes a command to display in which contexts an action can be executed.
    All that help me keep track of where I am and what I can do at runtime.
    I am sure that I will need more tools, maybe a way to display all the actions which can be executed in the current context, I will see what I need as I go on.

    You can do the same for the events.
    Just logging each fired event will help you track if the project is behaving as you think it should.
     
    hopeful and Luxgile like this.
  3. Luxgile

    Luxgile

    Joined:
    Nov 27, 2016
    Posts:
    16
    Okay that actually helped me a lot. If it's not to bothersome, can you explain a bit more the "Context" system and how to limit events with them?
     
  4. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    389
    First, I'd like to say that events aren't mandatory, nor are ScriptableObjects, they are just tools.
    If you do not know if events are a good tool for your project, I would advise you to look at some tutorials which explain what you can do with events.
    Avoid the tutorial explaining how events work, what you need is to find out if you have a use for them, and if you find out that you have a use for them, then you will learn how to use them, and create your own system to deal with events.

    I suggest these 2 videos:


    It's 1h30m total, but it's worth it (especially the second one).
    They will show you several different ways to use ScriptableObjects and events, and events configured by ScriptableObjects.



    Now, about the way I designed my 'Actions' and 'Contexts'.
    It's a thing I developed in order to manage keybinding more easily.
    A 'Context' is a state in fact, it indicates in which state the game is.
    An 'Action' (move forward for example) can be executed in one or several 'Contexts'.
    For example, the move forward 'Action' can be executed in the 'Context' InGame, but not in the 'Contexts' MainMenu or InGameMenu.

    When I do the keybinding I check that the same key ('W' for move forward for example) is not used for 2 'Actions' sharing the same 'Context'.
    For example:
    - the 'W' key is used for the move forward 'Action' which can be executed in the InGame 'Context'
    - the 'W' key is used for the 'Action' WinnerPool in the 'Context' MainMenu
    Then there's no conflict, because the 'W' key will not trigger 2 different 'Actions' within the same 'Context'.

    Of course, I can assign as many callbacks to an 'Action', so the 'Actions' are just an abstraction layer between a keypress (or a mouse-click, or an AI action, or a network event, etc.) and the code.


    In order to limit the events use, I have a list of 'Actions' to execute each frame.
    An 'Action' can be executed by calling its 'Execute()' method, which checks the current 'Context' and add the 'Action' to the list of 'Actions' to execute only if it's active.
    An 'Action' can also be executed by using the keyboard, in that case I check only the keys corresponding to the 'Actions' active in the current 'Context', and if the key is pressed, then I add the 'Action' to the list of 'Actions' to execute.
    Then, I execute all the actions of the frame and I clear the list for the next frame.
    That way, I ensure that an 'Action' can only be executed in its 'Contexts'.


    It means that I have completely separated any game-event in the game from the code.
    Whatever happen in the game is transformed in an 'Action', and then processed by a manager which process the actions in a central place.


    It's a bit hard to follow in the code, as the 'Action' and 'Context' are ScriptableObjects, meaning that I have to look into some data and not only in the code in order to follow an execution path.
    But it makes them easy to configure and to modify.
    And if I need to see what is happening with the 'Actions', I can place a breakpoint in the 'Actions' manager and see what is executed and what is not.


    As for the configuration, it means that I can create a new 'Context' using the Unity editor, along with 'ContextsGroups' (a list of 'Contexts'), drag&drop them wherever I need.
    Same thing for the 'Action', I create them in the Unity editor, I drag&drop 'Contexts' and/or 'ContextsGroups' in them, I can drag&drop GameObjects on it (these GameObjects must have an 'Execute' MonoBehaviour) and they will be automatically executed when the action is executed.
    I can also configure the default keys (if any) or the text displayed in the key-binding screen for the 'Action'/'Context' using the Unity Editor.
    I can also drag&drop a context on a specific MonoBehaviour on a GameObject indicating that all the 'Actions' placed on all the children of that GameObject can only be executed in that 'Context'.


    In fact, most of it is designed to be used in my game, I need to be able to separate the actions of the player, and to activate a bunch of them and disable others quite often.
    It's up to you to find out what are your needs, and then to implement them.



    But be sure of one thing: you will not implement what you need the first time.
    You will create a system, and at some point you'll have some unexpected needs and you will have to modify your system, and it will happen again and again.
    The idea is that each time you modify your system, you do less and less modifications, and at some point you'll end up using it without needing to modify it any further.
     
  5. Metalian

    Metalian

    Joined:
    Mar 4, 2017
    Posts:
    1
    Scriptable event system is ok but, is there an easy way to make a "Generic" Event System with Scriptable Objects? It would be useful to start with basic requirements then should have potential improve.
     
  6. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,633
    Not sure if this is what you are looking for, but there is this free project based on ideas given in Ryan Hipple's talk:

    Scriptable Object Architecture