Crave For Games


The text below is one of the notes from the StoneDrop development log. If you want a list of only technical articles you can go to the Articles page.
ScriptableObject use cases in Unity

Useful talk about ScriptableObject class usage in Unity.


Video 1. Overthrowing the MonoBehaviour Tyranny in a Glorious Scriptable Object Revolution. November 2016, Unite

Problems with MonoBehaviour:

- not applicable to shared states

- reset when exiting playmode

- sub-file granularity (a lot of MonoBehaviors in one file - as in scene or prefab)

- callback chaos (hard to track which MonoBehaviour were executed).

 

One of the solutions - uninstantiated prefabs, but:

- it's abusing the prefab concept

- accident-prone (easy to drop the prefab to a scene or add other components)

- still sub-file granularity (multiple components in one prefab).

 

The other one - C# static classes, but:

- no serialization (DIY)

- no visualization in editor (DIY)

- data will be lost on domain reload.

 

The proper solution - ScriptableObject (SO):

- not a component, cannot be attached to a GameObject

- does not get (most) callbacks

- can be serialized

- never reset at all (saved between playmode sessions, like materials)

- should be used for shared state (and referenced by non-shared states)

- can be created in memory by ScriptableObject.CreateInstance<...>()

- can be serialized by AssetDatabase.CreateAsset() or AssetDatabase.AddObjectToAsset()

- attribute [CreateAssetMenu] on SO will add "Asset/Create/..." menu in the editor

- OnEnable callback - when CreateInstance called or the object is loaded or SO is in the memory and scripts were recompiled in the editor

- OnDisable callback - before SO destruction or before domain shut down

- OnDestroy callback - only before destruction

- Destroy() or DestroyImmediate() will only remove native (C++) representation of SO which is a class (same for all SOs) handling referencing, id and serialization; the data is stored in managed (C#) part, so the only way to remove it is get rid of all references and run GC.Collect(). Keep in mind than == null operator is overridden and you really should do SO = null after destruction.

 

Patterns for SOs usage:

- alternative to database entries (tables)

- enums - created only to compare equality or to act like dictionary keys, extendable by designers, null support; also may be extended to be non-empty and store relevant data

- dual serialization - SOs fully supported by JsonUtility and can be (de)serialized to/from jsons which allows to integrate easy mechanism for user-created data sharing

- reload-proof singletons: before reload everything is serialized and stored (in native side), recompiled and then deserialized back, so SO can handle reload

- delegates (SOs with methods implementing interface or abstract class) which is easy to manage in the editor; yes, SO can be abstract.

This article in social networks: