- Home /
What is the purpose of ScriptableObject versus normal class?
Hey all,
This should be a pretty simple question. :) I think the documentation is pretty vague on this point, and only states that ScriptableObjects can be used when you *"want to create objects that don't need to be attached to game objects."*
Okay, so far so good. But how exactly does that make a ScriptableObject any different from any other class I define, and then instantiate objects of with the new keyword? Those are also pretty much "objects that don't need to be attached to game objects".
I understand that with ScriptableObject, I get access to inherited methods such as UnityEngine.Object's Destroy and DestroyImmediate, but what exactly do I gain from Destroy()'ing something as opposed to just setting its reference to null, and then letting the GC clean it up?
I've been defining and using lots and lots of my own classes and creating instances of them with the new-keyword all along, like any other programmer who's been trained outside Unity. But when I create a class, should I actually be inheriting from ScriptableObject all the time, and should I always be using Destroy when I want to release memory? I get this cold feeling running down my back that there's something here that it's seriously about time I understand right. >_<
Can anyone describe some examples where you've used ScriptableObject, and explain to what end?
"I get this cold feeling running down my back that there's something here that it's seriously about time I understand right."
I have this same feeling but I just use my regular classes without inheriting from ScriptableObject when I see fit so I don´t get bad (if it is a bad habit) habits from using Unity. Regular program$$anonymous$$g is still out there and I find some concepts confusing when program$$anonymous$$g in Unity C#.
for sass in response to Unity's vague documentation.
Answer by Bunny83 · Nov 30, 2011 at 01:13 PM
Serialization!
Unity uses it's own serialization methods to save and load objects. This serialization methods only supports classes that are derived from UnityEngine.Object.
You may say: "wait Unity can serialize every class with a [System.Serializable] attribute", well that's just partly true. If you have a MonoBehaviour class that has a public variable of your own class, Unity serializes the custom class as part of the MonoBehaviour. Unity doesn't take the true type into account.
If you have a variable of a base class in your MonoBehaviour but you hold an instance of a derived class, the class will be lost / converted into an instance of the base type when serialized / deserialized.
ScriptableObjects are true standalone objects. They are serialized on their own and the MonoBehaviour will just hold the reference to the instance, even when serialized.
If you don't need the serialization feature, use normal classes.
Keep in mind that if you want to use serialization Unity does serialize / deserialize your objects quite often.
Entering playmode: current scene is serialized, saved and immediately deserialized
Leaving playmode: The saved scene is deserialized.
Personally i don't like the ScriptableObject and Unitys serialization. Usually i use either my own way to serialize / save objects or use MonoBehaviours on empty GOs because it makes debugging easier ;).
Thanks a lot for a good answer, @Bunny83! :) I don't use/need the serialization features, though. $$anonymous$$y question was actually more memory-oriented. The one and only time I remember ever seeing Unity's memory consumption actually go down is when objects are disposed of using Destroy. Due to its non-generational nature, I can't remember ever seeing memory returned to the OS by the GC, and as far as I'm concerned, I think that garbage collector is laughably inferior and should be garbage collected itself. ;-) So the main reason I'm asking is actually if there's something to be won, memory-wise, from letting my classes inherit from ScriptableObject, since it seems using Destroy does something else than, say, implementing IDisposable in the .Net way.
I considered attaching $$anonymous$$onoBehaviors to empty GOs too, but refrained from it, because to be honest with you (no offense intended ;-) ), I think that's a little hackish. The fact that GameObjects all have transforms seems to suggest that they should always represent something visual or something that is a 3D entity in some manner. I'm not fond of the notion of abusing that just to get access to $$anonymous$$onoBehavior's callbacks.
:) Absolutely, it is hackish :D, but i actually had far too much trouble that Unity can't serialize my normal classes. I've build my nodebased editor completely on $$anonymous$$onoBehaviours and GameObjects. First i thought to attach all classes to one GameObject but in the end it's much easier to handle and to debug when each node is a seperate GO. I can also directly use the transform's position ;)
$$anonymous$$emory wise, well, Unity is written mostly in C++ so every managed (Unity) object have it's counterpart somewhere in the native code. That's why you have to / should use Destroy for those objects. If you have your own pure managed objects it's all handled by the GC.
Until now i didn't care much about memory consumption of Unity. If you want to keep the required memory small, use normal classes. All objects derived from UnityEngine.Object get some overhead (like an InstanceID, Hideflags, ...). I guess not all of them are carried over into the engine since they are only relevant for the editor but it's still something you don't need.
I'm not sure if Unity have problems to free unused memory. I guess it's not that simple because the whole $$anonymous$$ono-environment runs inside another application as some kind of plug-in :D. There are many instances that have to acquire memory from the instance above (If you are on a windows machine that means windows is the top most instance which could be literally the root of the problem :P).
So in conclusion, i don't have any special recommendations how to design your classes Unity-memory-management-friendly ;)
Answer by timbojones · Jan 21, 2017 at 06:45 AM
Use ScriptableObject to represent shipping static configuration data. Use normal objects to hold runtime data structures like priority queues, R/B trees etc.
For example, if you have many types of enemies in your game, make a ScriptableObject holding health, attack types, AI tuning, etc. If you have a crafting system, make ScriptableObjects to represent resources and recipes.
Populate your GameObject configuration using your ScriptableObjects as configuration containers, instead of exposing public fields across a bunch of different components. Use the [CreateAssetMenu] attribute on your ScriptableObject to add an entry to the Assets | Create menu.
Don't create ScriptableObjects with new. Create and load them using the Asset system.
Now, with a game designer hat on, you can churn out dozens of enemy variations or build a giant economy right in the editor.
With a bizdev or release management hat on, you can do some cool things with AssetBundles to support content patches, DLC, in-app purchases, etc.
The serialization story is actually important and you do use those features all the time: whenever Unity builds the game for you on the way to play mode. As your project grows larger in serialized size, your iteration speed goes down; your launch, load, and download times go up.
If you populate your scene with hundreds of entities that store configuration data with simple data types and Serializable objects, you'll get hundreds of copies of that data in your build. If you populate your scene with hundreds of entities referencing the same ScriptableObject, you'll get exactly one copy of it in your build.
Answer by RElam · Oct 16, 2015 at 09:42 PM
I use ScriptableObject cause Unity's editor really wants me to. If you wanted to reference an asset with a MyMonoBehavior instance on it that's intended to be a shared data set, you can do that, but the editor will not bring up a list of those objects when assigning it, forcing you to manually find it and drag/drop it. So if you had a concept like Material where you would like it to be a shared resource but also a usage unique/animated resource then you have to accept reduced usage quality or the hackey, bug spawning solutions like Renderer.Material/SharedMaterial.
IMO, ScriptableObject is a symptom of a design flaw, and I abhor using it... But I still do for the editor.
Answer by gdbjohnson3 · Mar 01, 2019 at 02:28 AM
Don't try to save references to SO's to a flat file tho (ie: serialize), since Unity doesn't retain the identifiers between builds. Sadly, this really cuts the usefulness of SO's in half, or even less than half. A great enhancement to Unity would be to reserve the internal identifiers for SO's so you can simply serialize references to them. I followed the tutorial about SO's where they claimed you can use SO's like Enums. Everything was great until I realized I need to serialize it, which required me to create my Enum list in C# anyways as a complete duplicate of my SO structure, and also then create a Dictionary lookup of Key to Data values, and create a reference list of them too on a GO. None of that would be needed if Unity just retained these internal id's...
so close... but still so far.