ScriptableObject
TypeClass
NamespaceUnityEngine
InheritsObject
Lives inThe Project window, as an .asset file

ScriptableObject

A ScriptableObject is a script that stores data as an asset file instead of living on a GameObject. Use it for things like weapon stats, item definitions, enemy types and game settings that many objects share.

A MonoBehaviour is a worker standing in the scene doing a job. A ScriptableObject is a recipe card in a filing cabinet. It doesn't do anything by itself, but any number of workers can read the same card. Change "Sword damage: 10" to 15 on the card, and every sword in the game uses 15. You don't have to visit each sword one by one.

Attributes

AttributeDescription
[CreateAssetMenu(fileName = "...", menuName = "...")]Put above the class. Adds an entry to the Project window's Create menu so you can make new asset files of this type.

Static Methods

MethodReturnsDescription
ScriptableObject.CreateInstance<T>()TCreates one in memory from code (not saved as a file). Use instead of new.

Messages

MessageWhen it's called
Awake()When the instance is created (for assets: when first loaded).
OnEnable()When the object is loaded. In the Editor, this also happens after every script recompile and when entering Play Mode.
OnDisable()When it goes out of scope or before a recompile.
OnValidate()Editor only: a value was changed in the Inspector.

ScriptableObjects do not get Update, Start, collisions or coroutines. They aren't in a scene.

Code Samples

1. Define the data

using UnityEngine;

[CreateAssetMenu(fileName = "NewWeapon", menuName = "Game/Weapon Data")]
public class WeaponData : ScriptableObject
{
    public string weaponName = "Sword";
    public int damage = 10;
    public float attackCooldown = 0.5f;
    public Sprite icon;
}

2. Create assets

In the Project window: right-click > Create > Game > Weapon Data. Make a few ("Sword", "Axe", "Dagger") and fill in their values in the Inspector.

3. Use it from a MonoBehaviour

using UnityEngine;

public class Weapon : MonoBehaviour
{
    [SerializeField] private WeaponData data; // drag an asset in here
    private float nextAttackTime;

    public void TryAttack(Health target)
    {
        if (Time.time < nextAttackTime) return;
        target.TakeDamage(data.damage);
        nextAttackTime = Time.time + data.attackCooldown;
    }
}

For more patterns (event channels, shared variables, runtime lists), see the ScriptableObjects in a Game tutorial.

What happens at runtime

  1. When a scene loads and a component references a ScriptableObject asset, Unity loads that asset once into memory.
  2. Every component that references the same asset gets the same object. 100 enemies with the same EnemyData share one copy, which saves memory compared to 100 copies of the same numbers.
  3. In the Editor: if your code changes a field during Play Mode, the change is saved to the asset file and stays after you stop playing.
  4. In a build: changes last only until the game closes. They are never saved to disk.
Not a save systemBecause of the two points above, don't use ScriptableObjects to save player progress. Use PlayerPrefs or write a file (e.g. JSON with JsonUtility).

Common Mistakes

See also