Search Unity

Scriptable Objects workflow

Discussion in 'Open Projects' started by Neonage, Oct 4, 2020.

  1. kcastagnini

    kcastagnini

    Joined:
    Dec 14, 2019
    Posts:
    61
    That's why I said that serializable generic fields in 2020.1 are a huge feature for custom inspectors, that was my point from the beginning.
     
    cirocontinisio likes this.
  2. Neonage

    Neonage

    Joined:
    May 22, 2020
    Posts:
    287
    I think we need discord when this kind of misunderstanding happens :)
     
    kcastagnini likes this.
  3. squarelover

    squarelover

    Joined:
    Nov 14, 2012
    Posts:
    31
    reading this thread is a waste of time. thx everybody
     
    hawaiian_lasagne likes this.
  4. SaltwaterAssembly

    SaltwaterAssembly

    Joined:
    Mar 8, 2016
    Posts:
    95
    What's the benefit of having an SO for different variables (float, int) etc, rather than say one SO containing multiple variables for a particular item (e.g. GameData variables: bool gameInProgress, bool gameOver) as examples?
     
  5. hawaiian_lasagne

    hawaiian_lasagne

    Joined:
    May 15, 2013
    Posts:
    124
    IMO it’s a nightmare when making everything so granular. I prefer larger beefy objects and less of them, rather than thousands of tiny ones. It depends if your abstraction is at a gameplay level or data level.

    One frustrating thing I find with SO is the inherit shared state they have, which makes them a bit flakey. For example, If I create a behaviour tree as a SO asset, and assign that to multiple agents, all the agents can seemlessly run the same behaviour tree and stomp each other’s state which is completely wrong. My expectation is they share the same data (tree node structure, node vars), but not runtime state, and there’s no clear way to do that. If I Instantiate/clone the SO for each agent, they now have their own state, but the data linkage is lost.
     
  6. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,659
    Yes, you have to separate the 'shared' data (the BT structure and 'constant' vars) from the runtime state. For instance, you'd have each individual user of the BT have their own reference to the current BT node, their own variables for which position in a sequence they are in or how much time they have left on a timeout node, etc. Your individual agents have to treat the shared asset data as read-only.
     
  7. cirocontinisio

    cirocontinisio

    Joined:
    Jun 20, 2016
    Posts:
    884
    @hawaiian_lasagne if you check out the state machine solution in the project, that's exactly what it does. Each Action and Condition starts from a ScriptableObject (the shared data part, such as the speed of a character) and instantiates at runtime an instance of a different class (not an SO, just a regular class) which holds the runtime data, unique to that state machine (such as, for instance, whether the character has reached a waypoint).

    This gives you uniqueness per character, while at the same time allowing you to fine tune gameplay values at runtime and, when you exit Play Mode, the value is retained in the shared SO.
     
  8. hawaiian_lasagne

    hawaiian_lasagne

    Joined:
    May 15, 2013
    Posts:
    124
    It’s quite convenient having the logic in SO aswell though, but as you’ve mentioned any logic state stored in the scriptable objects is shared also which is annoying. It means the tree structure can be represented as an asset, but then any state associated with those nodes has to be stored somewhere else, and I can’t think of a clean way to do that without duplicating the tree structure at runtime.
    I thought what might be cool is if the public properties of a scriptable object are treated as data and shared, but any private variables are instanced for runtime and unique to the thing that is using them. Obviously that’s not how c# works but just an idea.
     
  9. hawaiian_lasagne

    hawaiian_lasagne

    Joined:
    May 15, 2013
    Posts:
    124
    Oh thank you!! That sounds exactly like what I’m after I will check it out!
     
    cirocontinisio likes this.
  10. forestrf

    forestrf

    Joined:
    Aug 28, 2010
    Posts:
    231
    How does this work? For example, the AddUpForce SO. Where is that SO stored, in the scene? can they be stored inside prefabs too?
    If I want to have an enemy that uses events to relay data around its scripts, using a SO referenced by the script that signals the event and by all the scripts that receive that event, how do I do it so that the SO is unique for each enemy?
    The main reason I'm not using SO for things like this is because I don't know how to easily create and store SO as part of a scene or a prefab (if that's possible) and how to drag and drop easily between components (I even made this asset that, if I'm not wrong, would be the only way to drag an drop such a SO if it isn't stored in the project folder https://github.com/forestrf/DragAndDropFromField)
     
  11. Harsh-NJ

    Harsh-NJ

    Joined:
    May 1, 2020
    Posts:
    315
    SOs, Scriptable Objects are just .asset files, recognised by unity as an asset file. They are stored, or saved in the project, on the file system. They contain data, you can think them like of data containers. You can reference them in scripts and drag n drop them into inspector. You can easily create SO by creating a class inheriting from ScriptableObject class and adding a CreateAssetMenu attribute.

    Then you can right click in the project window and create your SO, then you can add some properties to the SO, reference them in a script, and access those properties. Say 10 gameobjects have a scripts with an integer value, which is supposed to be same for everyone, and is to be fine-tuned in play mode. You found a value, wrote in all 10 gameobjects inspector, and found it inaccurate. You need to repeat it every time.

    But, if you reference a SO there, you only need to change the SO's value, and all of the gameobjects will automatically change. Magic!

    Learn more here: https://learn.unity.com/tutcriptableobject-tutorial-getting-started

    https://www.raywenderlich.com/2826197-scriptableobject-tutorial-getting-started

    Hope this helps...
     
  12. forestrf

    forestrf

    Joined:
    Aug 28, 2010
    Posts:
    231
    Thank you. I have experience with SO as a way to store data in the project, as if it was any other asset, but I have no idea how to use it as others do, as a way to make an event system.
    Lets say I create a SO named "Enemy Goblin On Hit", then inside a prefab of an enemy (a goblin in this case) I reference this SO so both scripts that raise that event and react to that event.
    If now I spawn a single enemy, the event system will work well, but as soon as I spawn several enemies, they all share the same SO so they all will react to any of them getting hurt.

    Another example is using a SO to store the life of the player. What do you do if you have several plays in a split screen setup (local multiplayer)? They can't share the same ScriptableObject. Is it now not possible to use SO? Or can that SO be stored inside the player prefab, and somehow referenced correctly or idk. Just how can that be done?

    The example of swords and selecting them shown in https://www.raywenderlich.com/2826197-scriptableobject-tutorial-getting-started would also not work with local multiplayer
     
  13. alejandro7120

    alejandro7120

    Joined:
    Mar 18, 2020
    Posts:
    1
    Hi everyone and thank you for creating these great projects!
    I have been reviewing and using certain systems that have been implemented in the project, such as the event system and the sound system but I have come across a problem that I would like to know how it has been solved in your project since (due to my inexperience I suppose) I have not found it, it happens that in places where we define the ScriptableObjects the OnDisable () function is used but in my case this function is never called and searching the network and by logic itself I understand that this type of functions are called differently than in a Monobehavior
     
  14. Harsh-NJ

    Harsh-NJ

    Joined:
    May 1, 2020
    Posts:
    315
    Hey @forestrf, nice counter examples. But for your Golblin example, you could add an parameter to the SO event of type Gameobject, and pass the Goblin gameObject. That way you play animation, audio or anything else only if

    this.gameObject == eventSO.gameObject

    or anything else applicable.
    One can do the same thing for the multiplayer example, passing and playerID, or something like that.
    Thanks
     
  15. Harsh-NJ

    Harsh-NJ

    Joined:
    May 1, 2020
    Posts:
    315
    I think these are called when the game is stopped playing...
     
  16. cirocontinisio

    cirocontinisio

    Joined:
    Jun 20, 2016
    Posts:
    884
    Yes, the OnDisable of ScriptableObjects is slightly different from MBs, but not that much.

    The docs have the info: https://docs.unity3d.com/ScriptReference/ScriptableObject.OnDisable.html
    As mentioned, the OnDisable / OnEnable are called when scripts recompile, allowing you to "start fresh" and reset any state of the SO you might desire.

    Also I don't know if you know, but you can create and destroy SOs at runtime, not only in the editor. The docs above offer an example:
    test = (ScriptObj)ScriptableObject.CreateInstance(typeof(ScriptObj));


    And likewise, you can destroy one. In this occasion, OnDisable would be called.