What is it with Unity's recent infatuation with Scriptable Objects?

They mainly serve as data stores when you would normally have public variables or some other database solution to hold data.

They are a little tricky to set up at first but after a few times you will be using them for everything. It’s strangely addictive to use them!

I like the fact that they are serialized at editor runtime as well so you can hit play and make a few changes and the changes are still there when you hit stop on the editor.

One thing that was pretty great, in my opinion, was adding ‘CreateAssetMenu’. :slight_smile:

2 Likes

Yeah it was a PITA to use them before that was added.

Wow! Thanks everybody for all the great info and suggestions!

What’s the difference? A scriptable object doesn’t have the Transform wasting space at the top, and has a picture that makes explicit what it’s for (but you can name your prefab “house1data” and put it in a folder named “prefabsThatAreReallyJustData”.) Is there any other difference between a never-spawn-me prefab and an SO?

But I don’t think I’ve ever made a pure-data prefab. I think because in practice linking to a real prefab is often fine. Your gun can link to the bullet prefab it wishes to fire. Yes, you’re needlessly copying static bullet data with each bullet, but probably not much. And you don’t always know what data is per-instance vs. per-type at first.

The big difference is displaying your intent to other people.

If I make a ScriptableObject class, my coworkers knows that the type represents an asset without ever having to talk with me. If I make a MonoBehaviour and stick it on a prefab in order to represent the same thing, then they’ll have to do some spelunking to understand what’s going on, and how it’s supposed to be used.

2 Likes

But do you see the OP’s confusion? If you’re already using prefabs to put serialized data in Assets, then the advantage of ScriptableObjects is “no added functionality, looks a little nicer.” So what’s with all these lengthy articles? I think Baste is selling co-workers short. Sure, many game designers are code-phobic, but they’re great at abusing anything through a GUI. “abusing these prefabs for data” shouldn’t be a stretch (if you’re forced to use an early version of Unity?)

These examples about the wonderful things SO’s ~allow~ you to do are really someone finally realizing you can break data into linked parts. Which is great. But it’s like someone who’s never seen x=x+3; getting very excited about +=.

The danger is you fall into the trap of thinking things can only do what they’re “supposed” to do. If you think of it as the SciptableObject trick and not the “link to shared data” trick, you might miss how your prefab can link to an SO, and another prefab, and a class instance built from a file and get linked on spawn to a script on a gameObject. And it’s all the same pointer-trick and all works the same way.

It’s more about vastly better design than looking nice or adding functionality.

Say we have a cow class, a tail class and 3 types of cow tails. I think you’re imagining pre-scriptableObjects where each cowScript on a gameObject had its own tailScript, filled in one of 3 ways. We never did that. We always created 3 global instances of the tail class and had every cow reference the global tail it wanted.

A common way was making a tail-holder gameObject with an array of 3 tails. A cow could point to it’s tail using public int myTailNum. It was a little awkward, but it worked (awkward bits: looking up your stats through that GO: tailHolderGO.Tails[myTailNum].swishSpeed. Making sure the gameObject was in all scenes. Remembering which tailNum was which tail - but a custom Inspector could handle that.)

The prefab method held the 3 tailScripts using 3 empty “dont-spawn-me” prefabs. It’s the same as the scriptableObject method: cow code has public tailScript myTail;. That links to one of the fake-prefab tails. Use myTail.swishSpeed to read data. If feels different from an SO since you don’t normally read the inside of a prefab. But they’re both just classes.

I would just make the tail an SO, put the swish behavior in it, then call someCow.Tail.DoSwish();

New tails would inherit from the BaseTail so the implementation of Tail never changes but the behavior is swapped by just pointing at a different SO of type BaseTail

Yes, but that’s the exact same thing people were doing 5 years ago using gameObjects to hold the tails. Once you can find a class, it doesn’t matter if it was on a gameObject, or prefab or an scriptableObject. You can store simple data, write member functions … classes are classes.

Same thing. Inheritance works equally well when the class is in an array on a gameObject, on a prefab, or on an SO. The Unity Inspector enjoys them equally.

There’s nothing wrong with what you’re doing - it’s the same thing programmers have been doing forever. And SO’s are 5% nicer for many things. But if you think it requires scriptableObjects you’re limiting yourself. You could be doing better. For example coroutines need to run from a gameObject. Knowing this trick works just fine with empty gameObject holders might be good to know.

Except that the GOs have other implications, for example when the hierarchy moves, they sending messages back and forth and calculate bounding boxes, etc. A pure coding class has no place in the visible part. GOs for visible items SOs for coding.

2 Likes

This is why there’s a talk on SOs every Unite.

1 Like