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 КомментарииПодписаться на комментарии