Making cool stuff with ScriptableObjects

I’m Matt Schell, the Senior Screencaster on the Online Evangelism team at Unity. I make stuff in Unity and teach others how to do it via our Twitch channel and on YouTube. I’ve produced some online video training using ScriptableObjects and thought it would be cool to put them together in a blog post, along with a few related Unite talks by people much smarter than me, and so here we are!

I had been programming in Unity for a decent amount of time before I learned about ScriptableObjects. I would not call them something that beginners urgently need to know when getting started. When I did learn about them, however, I got ScriptableObject fever. I really began to use them a lot. They offer an interesting set of tools to extend your programming toolkit in Unity and helped me to think about certain architectural problems I’d been having in my projects a little differently. Overall, I find them to be very helpful.

So what are they? To quote the manual “A class you can derive from if you want to create objects that don’t need to be attached to game objects.” This is a good start, I’d add to this that they allow you to create objects which are assets which can either hold custom data or execute code.

One example would be to create a custom asset that holds all the statistics for a given enemy type. Say you want to change the maximum speed of all those enemies. You could simply edit a single value on our ScriptableObject asset, as opposed to having those values stored in the public fields of a MonoBehaviour attached to an enemy prefab or prefabs. This can help with both the centralization of data and version control. These values also persist after being changed in play mode, since we are changing a value on an asset.

Another way that we can use them is to create assets which hold executable code. An example of this is seen in the video series below showing the Pluggable AI System. All of the pieces of code which compose the AI behavior are stored in ScriptableObject assets, which you can then configure and combine in the Inspector, without writing additional code.

I learned about ScriptableObjects and was inspired to begin using them by watching my colleague Richard Fine’s excellent Unite talk on the subject “Overthrowing the MonoBehaviour Tyranny In a Glorious Scriptable Object Revolution”. For a ground-up primer on what they are, how they work and some example use cases, I highly recommend you check it out. Also that title, wow.

One of the use cases that Richard demonstrates in this talk is a pluggable AI system with different ‘brains’ that can be plugged into AI tanks. I thought this concept was really fascinating and dug into his public source code to see how he had put it together. Once I understood the pattern I thought it would be really interesting to create a variant of his idea. I wanted to also allow the configuration of those ‘brains’ and the creation of variants and styles of behavior using a similar ‘pluggable’ approach. The result is my own Pluggable AI With Scriptable Objects Live Training Session. I won’t claim to have improved on Richard’s work or idea, but I very much enjoyed creating the system and I have used it in some personal projects with results I am happy with. Adding a nice Editor Window or Inspector to enable easier, more elegant editing and configuration would be a way to make it even more beautiful. I hope to be able to do this someday in the future (maybe) ((no promises!)) :)

The Pluggable AI system is, I think, a nice example of the ‘modular code asset’ style of using ScriptableObjects, but importantly, ScriptableObjects can simply be used as custom data containers as well, to great effect. I used them for this purpose to create a similar pluggable architecture, in my Text Adventure Live Training series. Creating a Text Adventure game in Unity is, of course, massive overkill. You don’t need a powerful 3D engine to make such a game, but I found it to be a very fun programming exercise and many folks who follow our content on YouTube seemed to enjoy it as well. This project provided a nice opportunity from a teaching perspective to present some ideas about architecture and patterns, including the use of ScriptableObjects, that I think would have been difficult in a more visual style of game. In this case, I used ScriptableObjects to create custom data asset types for each ‘room’ in the game. I also used them to create each item, possible action, and action response. This meant that if I was on a team with a programmer and a game designer, for example, the programmer could create custom asset types, and then the designer could create instances of those types, for example, rooms, and populate them with descriptions, exits, and interactable items, all via editing in the Inspector. I thought this was a fun idea and a neat option to build an architecture in which all the pieces of your game could avoid becoming tightly coupled together in written code, allowing non-programmers to interact with it more readily. I wouldn’t propose to say that this is the only or even the best way to structure such a system, but certainly that it wasn’t the worst and it was fun to make, think about and work with.

The last video I wanted to share and talk briefly about is the newest. It’s a video of a talk at Unite Austin by Ryan Hipple of Schell Games (no relation!) I recommend watching Richard Fine’s talk first, before watching Hipple’s talk since Hipple makes reference to Fine’s and builds on some of the fundamentals Fine has laid out. I find myself very inspired after watching this talk to try out some of the concepts that Hipple describes.

﻿

One concept that I found very interesting was the idea of putting variables, like for example a single float value, into ScriptableObjects. We can then create assets out of these ScriptableObjects. The image below shows an example of this. The Player references a ScriptableObject asset which contains a single float variable, for example, containing the Player’s health. The other systems in the game reference this asset and get the current value from it, as opposed to referencing the ‘PlayerHealth’ component directly via code. This allows for the objects to all be coupled together in the Inspector instead of via hard-coded references. I was so taken with this idea that I asked Richard Fine if he saw some hidden down-side to it and he said that besides the fact that you’d have to make sure you reset each value via script manually (probably upon exiting play mode), it seemed reasonable.

Personally, I really like the aesthetic of having lots of little objects you plug together in the Inspector. It seems, to me, less failure prone. I feel like it will also cause me to write less bad spaghetti code, which hard links all kinds of systems together in grotesque ways (something I am sadly prone to do). Of course I recognize that these kind of architectural decisions are highly aesthetic and almost religious in people’s desire to believe that theirs is the best, so of course, your mileage may vary. I for one have already been moving in this direction in my personal game project and so found this to be quite a cool idea. Maybe I’ll report back after I’ve tried it, or incorporate it into some upcoming material in my role as an Online Evangelist.

Generally speaking, if you’re at the stage where you’re moving from creating small demos and prototypes into something larger destined for release, I think it’s a good idea to understand what ScriptableObjects are and how they can improve your workflow and architecture. I know that using them myself has allowed me to move away from doing a lot of gross, hacky-feeling things in my own projects and move in a more modular, elegant direction. Or so I think! What are your experiences with ScriptableObjects? Do you love them? Hate them? Please post a comment below, I’d be curious to hear your thoughts.

34 Comentarios

I still have a hard time understanding what ScriptableObject is. I don’t understand how it works since it’s not a Monobehaviour script and how ScriptableObject interacts with GameObjects and other ScriptableObjects.
All Unity videos and tutorials on the subject doesn’t help a lot :(

They don’t interact with game objects inherently. They exist as assets in your project files, just like scenes and materials. You can reference those assets from other scripts, just like any asset. They can just be containers of data, which can be customized in the inspector, or they can have functions and logic in them as well.

One of my biggest grievances against Unity is how it needs things to be attached to a game object. This threw me off when I first started Unity, and while I got used to it over time, I’ve always wished that this would change.

Thanks Mario, glad you enjoyed the post. I think ScriptableObjects are a cool way to not have every single thing be a component, but still work the way Unity ‘wants’ you to and not do crazy workarounds.

One important thing to keep in mind while working with SO:
-Changes made while playing in the editor are saved.
-Changes made while playing in a build are not saved.
ScriptableObject are assets. Once you created a build, the assets in the build cannot change.

By experience, i’m using ScriptableObjects only as configuration files (to store data that are not changing) not to save data.

Also if you want to change the data in your ScriptableObject while playing but want a reset when exiting play mode there is a simple way. Because ScriptableObject are UnityObject you just have to create a copy at runtime with “ScriptableObject copy = Instantiate(myScriptableObject)” and work with this copy at runtime.

Really interesting. I was wondering why Variable and ReferenceVariable do not dispatch an event like “OnChanged”. For example, when a FloatVariable value is change it could invoke a UnityEvent (or Action). A VariableReference could listen that event and dispatch the same one. The point would be to avoid script that need to update when a variable is change to check in an Update method. Using a UnityEvent inside a VariableReference would allow to select the callback right from the editor.
Does that make sense ?

I agree that there’s a degree of opacity in these systems, although IMO not much worse than what you’d have in certain text based code. For my pluggable AI system I would like at some point to try to create some kind of more elegant UI via editor scripting to make connections and the state of the system more visible.

I agree that Unity has a ways to go in terms of best supporting non-programmer disciplines, including designers and artists. All I can say is that it’s something we are aware of internally and working to improve.

I have actually been experimenting with a shared data approach, same as in the blog, and am surprised I overlooked the use of Scriptable Objects. Cool idea!

Another great use of Scriptable Objects is in editor code. With normal windows you cannot save the state of your configuration when using a tool without using Player Prefs or some other method. So if you want to re-use the tool to perform some action in the editor at a later date (after you have closed and reopened Unity), you have to re-configure the tool. However, you can write custom inspectors for scriptable objects implementing the same logic as in editor windows, and you get a place to save configuration data for free. You can then duplicate those scriptable object assets and make small changes to run the tool with a slightly different configuration.

I use ScriptableObjects for mostly anything that needs to be stored in a centralized location. Most recently I took advantage of the fact that you can use them as persistent polymorphic objects. I created an Event System which can be used for AI (similar to your example), or just as a GUI friendly drag and drop scripting option. It makes use of a bytecode pattern, and the fact that ScriptableObjects instances can be serialized inside of a scene (!!) to create scripted sequences of events. I find them incredibly useful and hope to see more features brought to them overtime.

Glad to hear it! I personally like the drag and drop architecture and find it to be ‘Unity like’ in that it seems to work with the way Unity is designed as opposed to around it. Of course, others prefer other approaches, but this works for me pretty well. – Matt

YAAAAS! My current project has reached a phase where the spaghetti-code nature of it led me to look for a better way and I ALSO found Richard Fine and Ryan Hipple’s talks super useful! I particularly like the brain/destruction examples Richard has and Ryan’s event system using scriptable objects. The thing I find very confusing about nested scriptable objects are how they are handled differently between the play mode editor and after compiling??? Another thing I find confusing is I noticed that Richard Fine’s example essentially uses a singleton pattern in order to load up the scriptable objects and access them from the UI but then Ryan Hipple’s talk goes heavy-rant style into the horribleness of singletons… I wonder how should UI scriptableObject data… like PlayerName be accessed if not from singletons using scriptable objects?
The thing I am working on now is extending the Ryan Hipple event system and listener to become kind of a SceneFlowManager – where a series of events happen and then trigger resulting actions (code). For example, scene loads – pop the default player info User interface – then player saves – fire up the networking code and find a nearby game to join – then after player chooses server, launch into the game. Ideally I could handle this flow via a scriptable object so that I can have lots of different flows per different scenes and I can make changes to them quickly later.
Anyway, I love the blog article and hope to see more on scriptable objects in the future.
Thanks!

I haven’t used one singleton yet. For playername and other things like these, I keep a StringValue SO, reference it in all the components that need to know the name, and the one component that updates it from SteamDotNet simply writes to it.
Now what you end up with is either update loopy thing to check for change :( or out of synch clients :(( so to solve that I added an event that gets invoked when the varibale gets set. Now those components that absolutely must be in synch with the variable just have listen to the playerNameChanged event.

I think the singleton / no singleton question is basically a matter of aesthetic taste. ScriptableObjects can be used in either scenario for a variety of reasons. I thought Hipple’s example for shared variables was cool because it solves certain problems I’ve had in the singleton architecture of my current personal game project, namely that certain data and references may not be available at certain times, race conditions and similar problems. Importantly, I don’t think any of this stuff is a ‘comprehensive best pattern for game architecture’ but instead a whole series of tools that can be implemented in a variety of architectures and cases. Basically, my hope is that learning about these things expand the range of solutions you have to your architecture problems, and then you can choose what you find appropriate for your game. – Matt Schell

I have developed a deep hatred of singletons over the years. In reality that hatred probably comes more from experiencing an overuse of the anti-pattern rather than the problems inherent to singletons. To that end, I do not believe that any one pattern should be used to solve all problems, including this.

The last few projects I shipped made no use of singletons and I do not see myself going back. Identifying a problem to solve and then matching it to the best solution should always be the decision process for game architecture. Relying on crutch solutions like singletons may seem like the fastest solve at the time, but you will pay for it later.

To address your scenario, how does UI look up a SO variable if not with a singleton, I would suggest giving the UI script a public (or private serializable) StringVariable field. In the inspector, point that field to your PlayerName SO.

I do have a solutions regarding the resetting of the value when playmode stops. The samples I put together for the presentation are simplified versions of what I put in games. To make sure play-mode changes do not get saved back to the assets, you simply make a RuntimeValue field that you access from other scripts. RuntimeValue can be initialized from Value when it is accessed or synced up in editor time with an OnValidate call if you want to get a little fancier. I freaking love OnValidate.

This way, you do not see all of your assets change every time you play in the editor.

Thanks for the additional info Ryan! Loved the talk and definitely got my wheels spinning. I’ve also done some stuff with OnValidate in combination with ScriptableObjects and agree it can be a cool combination.

“I would not call them something that beginners urgently need to know when getting started.”
Yes, but right after they get started, I think they should learn about them.
There are so many benefits about using them, and they are an important tool in unity’s tool set for making games.
To learn how to use an tool it is important to… use it! And I wish more and more future unity’s tutorials include scriptable objects in them.
That’s my opinion anyway.

As you can see, I basically agree with your opinion :) I am trying to wave the ScriptableObject flag as much as I can within the internal Unity learning ecosystem and agree that they are a great tool for people to learn about.

Used scriptable objects as intelligent databases for ages, and more recently have been playing around with using them in place of variables that will be referenced by more than one object.

While its a nice way to do things, it relies on:

– You making an editor script to reset values + track initial (startup) values
– Intelligently tracking changes, as a change to the data will affect all links to it
– Accidentally deleting the asset literally removes the variable from every script that references it

Ultimately I think that if you will take this approach, you need to fully buy into it, otherwise its cumbersome. But if you struggle to link systems together cleanly and coherently, I recommend trying this approach!

I agree that like every system, it comes with some overhead. And I think some games will benefit from this more than others. My hope by sharing the patterns is that it allows people to make more enlightened choices about their game architecture, especially for those who are just getting started making bigger scale projects in Unity.

When I first learned about these a few years ago my world turned upside down. I tried so many systems to keep track of data (JSON, XML, CSV, SQL) and they were all a huge chore with many hangups. Scriptable objects are a god send and lets me directly store model data including complex entities like Sprites (without hardcoding a path but rather a direct link to the object). Thank you thank you thank you!!!