Using ScriptableObject for data objects in Unity scenes

When you start developing with Unity, one of the basic thing you need to get your head around is the way Unity handles classes and data for your game.

I’m not going to in the details — you should read the great blog post at Unity3d.com about the serialization here. (They really should do a blog post / tutorial / documentation about how to store your data, like a flow chart to decide where to put your data ūüôā )

Common Data, Common Problem

Common problem is where to put data that you need to share between components. A neat solution for persistent, config-kind-of-data is to put it in a custom ScriptableObject that then is saved to the asset database. You can then reference this data from the components in the scene, and they all will share same values. For example if you need team colors (red and blue) instead of sprinkling the colors to every possible component you can just have a reference to a TeamColor ScriptableObject and keep the color there Рthe same way you do with PhysicsMaterial for example. I usually have a GameDatabase asset which contains the global configurable parameters for the game. This data can be anything like lists of enemy prefab names, in-game shop configuration, list of chapters and levels in the game and their respective scene names etc.

Scene Only, Please

But what if you need to have shared data in the scene? You might not want to create assets for each data in each of the scene, as this makes the asset database cluttered with data only relevant to a certain scene.

I guess many developers don’t know that they can actually instantiate ScriptableObjects and have them exist only in the scene.¬†If ScriptableObject is referenced by the scene and stored as an asset in the asset database, only a reference to the asset is stored in the scene file. But if ScriptableObject is NOT in the asset database, it actually gets serialized into the scene file. Let’s call these kind of ScriptableObjects by Scene ScriptableObjects (SSO’s ūüôā ). Note: this same applies to any assets, not only ScriptableObjects. You can also embed textures and meshes in scene files, many times by accident.

Having said that I haven’t used this feature much. Usually I end up putting scene specific data into a single component in the scene in some GameObject. For example if the each scene is a level in a game, I have a LevelInfo component that resides in a GameObject called “_levelInfo”. And all of the data goes there. Why do I do this? Let’s first see how to use ScriptableObject that goes only in a scene file.

How To

What we need first a the ScriptableObject to use:

using UnityEngine;
using System.Collections;
public class SOExample : ScriptableObject
{
public string text;
}

view raw
SOExample.cs
hosted with ❤ by GitHub

Then let’s create a component that holds a reference to this ScriptableObject. Note that this code creates a new ScriptableObject if it doesn’t have a reference. So by default each SOExampleBehaviour will have instance of their own SOExample:

using UnityEngine;
using System.Collections;
public class SOExampleBehaviour : MonoBehaviour
{
public SOExample test;
public void OnEnable()
{
// instantiate if needed
if (test == null)
test = ScriptableObject.CreateInstance<SOExample>();
}
}

If you now create a new GameObject and attach the SOExampleBehaviour script to it, you will see something like this:

so1

If you now double click the (SOExample) value in the behaviour, you will be able to inspect the ScriptableObject itself, and type a value to the text field :

so2

Now, if you save that scene and open it in a text editor (assuming that you’re using text serialization for the assets in Unity), you will see something like this:

….
— !u!114 &819407913 <<— this is our ScriptableObject id in the scene
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4a48e9db79a952f419ca79d71a03fe31, type: 3}
m_Name:
m_EditorClassIdentifier:
text: LOL <<— the text typed in the SO
….
— !u!114 &1539014338
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 1539014337}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3032752457dc4fc438051e79d2e9d38f, type: 3}
m_Name:
m_EditorClassIdentifier:
test: {fileID: 819407913} <<— reference to the SO

view raw
SOExample scene
hosted with ❤ by GitHub

Nice, right? ..right?

Well, technically yes. But there’s a major UI/access problem.

 Accessing Scene ScriptableObjects

The first thing we want to do now is to share data between multiple instances of the behaviour. Just make a¬†new¬†game object and add the SOExampleBehaviour¬†and BOOM! You have another instance of the SOExample¬†— not what we wanted.

We can fix this easily, right? Just click the bull’s eye on the another and find the correct instance. The problem is that the scene finder will give you nothing:

os3

This is a major problem. It’s not even possible to drag the SOExample from first behaviour to the second behaviour. Normally this would work as the GameObjects and Components have spatial representation, but ScriptableObjects do not (unless they’re saved as assets).

We can’t access the scene¬†ScriptableObjects in any other way than using code. So let’s modify the SOExampleBehaviour a bit:

using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class SOExampleBehaviour : MonoBehaviour
{
public SOExample test;
public void OnEnable()
{
// find existing instance if needed
if (test == null)
test = Object.FindObjectOfType<SOExample>();
// then instantiate if needed
if (test == null)
test = ScriptableObject.CreateInstance<SOExample>();
}
}

Notice that I added [ExecuteInEditMode] to OnEnable work every time I tick the enabled flag for the component.

Which One of You I Meant

I’m also using Object.Find<SOExample>() to find a single instance of a SOExample, but I have no way of knowing which instance I get. If you already duplicated the SOExampleBehaviour previously, you’ll now have two instances of SOExample laying around and Unity returns either one by random. And if you need more than one instances of same type of ScriptableObject, you’re in trouble.

Conclusion

So using ScriptableObjects for shared data inside scene files is far from optimal, but possible. The problems are mainly UI/access issues. Nice thing about using ScriptableObjects in scenes is that you can later convert them into assets stored in the asset database, to be shared between scenes.

You probably understand why I’m not using SSO’s ūüôā Instead, I just create these specific data-only behaviours that I add to each scene. They get a GameObject and Transform (and they’re spatial), which is a bit of a waste. However, this hasn’t been a real issue, as the number of these objects is usually very limited. But on principle, it’s wrong.

NOTE: You can spawn and use¬†ScriptableObjects also run-time. However, because if you only need something during run-time, you don’t need that data to be serialized and using ScriptableObject for that does very little sense. It’s better to use plain C# classes for that.

ScriptableObjects do have one slight advantage over plain C# classes for run-time, and that is support for inspector. If you want inspector for plain C# data structures, you need to implement a custom editor, which can be quite tedious.

Also, I’m not sure how run-time ScriptableObjects behave during hot-loading (i.e. compiling scripts while the game is running inside editor), but I guess they would work better than plain C# classes which simply get wiped out due to the serialization.

In short: You can use ScriptableObjects for storing shared data inside scenes, but currently it’s clumsy and you should use other means like data-only behaviours or ScriptableObjects stored as assets.

Room for Improvement

Here are some issues I’d like to see addressed in the future regarding the ScriptableObjects:

  • Out of the box, it’s really difficult to instantiate ScriptableObjects when you’re using them as assets — you need to create or use custom editor code just for this purpose. It should be possible to spawn them using editor alone.
  • Finding and assigning scene ScriptableObjects is impossible, again without code. And even with code you can’t really pick specific instances if you have spawned more than one instance. The object finder in editor should list you all the SO instances in the scene (if you’re modifying a field for a scene object, that is)
  • There should be a view for the SSO’s similar to the scene hierarchy view, which you could then use to assign the SSO’s to behaviours.
  • SSO’s can be named in code, but the inspector for ScriptableObjects doesn’t display the SSO’s name, making working with multiple SSO’s really confusing…
  • Converting a SSO to an asset should be just matter of drag-n-drop, just the way like creating prefabs works.
  • The documentation. Don’t even get me started ūüôā The documentation is lacking, to put it mildly.

There. Hope this helps someone…

PS. Motivation for this post was Adam’s post about lack of support for runtime objects:¬†http://t-machine.org/index.php/2015/03/28/unity3ds-missing-core-no-runtime-objects

Combining Physics and Animation in Unity

Working with animations is easy in Unity, and so is working with physics. However when you combine those two, things can go haywire. I wanted to write a short post about it and how to avoid some of the potential pitfalls.

If TL;DR: scroll down and read the summarum and check out the Unity webplayer demonstration.

Understanding Time in Unity

It’s a fundamental thing to understand how time works in Unity. In one hand you have the regular, variable time step update loop which is governed by the rendering, and on the other hand you have the physics, fixed time step update loop which is governed by the physics engine. Because of their nature, they’re never quite in sync. This means that there are basically two instances of the same universe but in different time!

From regular world to physics world

By default the animations are updated in the regular update loop. This is perfectly fine, and gives us smooth visual results. However, because the time in physics world is different, objects updated in the regular update loop appear to move erratically in the physics world. If you’ve ever animated a collider and placed some physics objects on top of it, you might know what this means. physicsanimation_inspectorLuckily this can be solved by forcing the animation to be updated in the physics loop – just use the Animate Physics setting in either Animator or Animation component.

The caveat with this is that once you go from the regular update to the physics update, you will start to get small jitter in the motion as the physics is never perfectly in sync with regular update. Again, luckily this can be solved with interpolation modes (see below).

Moving versus Reappearing

Once you set the animation to update in the physics loop, the physics engine sees the collider being updated at regular intervals. At every frame, the collider’s position is updated as dictated by the animation. That’s all we need, right? Unfortunately this doesn’t mean that the physics sees the collider moving. In fact, what the physics engine just sees is a collider without a rigidbody¬†disappearing from somewhere, and appearing at someplace else! In physics perspective, the collider doesn’t have any movement speed, and it’s not moving in any direction. This will cause some issues.

First, because the collider is disappearing and appearing, there’s a great probability that the new position of the collider is actually intersecting with some of the rigidbodies in the world, causing erratic collisions and potential fall-throughs.

Secondly, if the animated collider is moving underneath some rigidbodies, there is no friction at play at all. This means that collider is simply sliding under those rigidbodies on top of it, leaving them be.

So how to fix it? Simple. Just add a rigidbody to the animated collider and you’re set. This ensures that the collider has a proper physical response. Remember to set it to kinematic!

Getting Really Out of Sync!

It’s a noble goal to have your update loop and fixed update loop are running somewhat at the same pace (say, 60Hz) – everything looks smooth and jitter-free. But when your update loop ¬†rate is nothing near a multiple of the fixed update loop rate, you start to see sync problems.

Quick example: let’s say your regular update is running about 45 FPS (22.22ms delta time) while you have set the physics to run at 60 Hz (16.66ms delta time). ¬†This means that roughly for every 3 regular updates there will be 4 physics updates. And because there can be only integer number of physics updates per frame, this means that two of the frames will have 1 physics update and one will have 2 updates. ¬†It gets even worse with 40 FPS regular update rate and 60 Hz physics update rate (why?)

On the other hand, if you lower your physics update rate to something like 10 Hz (which you really should, just to test your game physics), you get opposite effect. There will be frames where physics is not updated at all. If you rely on the fact that FixedUpdate gets called every frame just because your FPS is lower than your physics update rate, don’t! Bugs are known to exists because of that ūüôā

Past or future?

physicsanimation_interpolationWhile these settings fix the physics side of things, the physics animation is more or less  out of sync from the visual representation every frame. For this Unity offers a way to interpolate the position of rigidbody for the regular update. There are two modes: interpolation and extrapolation. (The interpolation mode is not only for animation, it works with any rigidbody)

Interpolation means that the position for the object is calculated by taking the current update time, and moving it backwards one physics update delta time. Now there are at least two physics updates: one behind the chosen time and one ahead. Unity simply interpolates between those two updates to conceive a position which it then uses for the update position. This means that the interpolation is actually lagging behind one physics update! But it’s guaranteed to be rather smooth.

The other option is to use extrapolation. Instead of using those two physics updates and interpolate between them, Unity uses them to predict the future position for the object. While this doesn’t suffer from a lag, it’s unfortunately unable to see in the future correctly, causing a visual jitter when the prediction fails. And it will fail often, especially in sudden changes in motion (like collisions…)

Summarum

Here are my recipe for solid physics-compatible animation in Unity:

  • Add rigidbody to the animated collider for proper physics response and set it kinematic because of the animations (thanks T.M)
  • Set the animation to run in the physics update (Animate Physics)
  • Use interpolation for smooth visuals if needed
  • Aim for same (or integer multiple) regular update and physics update rates where possible (i.e. 60Hz or 30FPS/60Hz etc)

Demonstration

I’ve created a small Unity webplayer demonstration to easy testing how these settings affect the physics stability.

You can check it out here (http://sampsy.com/blog/physicsanimation.html)

There is a simple setup with a cube, a sphere and an animated platform. With the UI you can setup various things for the platform.

Be sure to test out all the settings and their combinations. Try these:

  • No rigidbody, with or without physics animation (default settings). Objects stay in place, platform sliding beneath. When the platform rises, sphere simply goes through it.
  • With rigidbody but no physics animation: The cube stays properly on the platform, but jitters noticeably. With 10Hz physics the cube gets really wonky.
  • With rigidbody and physics animation: The cube stays on the platform as expected, sphere rolls and falls as expected. Works well even in 10Hz physics rate!
  • No rigidbody, fast animation, 10Hz physics rate: Objects simply fall immediately through the platform as it moves into them.
  • (Also test out the interpolation modes for the platform)

That’s it. If you have any feedback, leave it here or in twitter (@snlehton).

Unity Physics Gameplay

On 8th Oct 2013 I gave a short talk about Unity Physics Gameplay at the IGDA Finland October meeting. In case you want to check out the slides, they are here: IGDA_Oct13_Unity_Physics_Gameplay_20131009

I have an intention to expand this talk to a series of Unity physics related posts, but we’ll see how that turns out.

In case you have questions about the slides, add comments here, or contact me in Twitter @snlehton or by email sampsa.lehtonen [at] iki.fi