Data Assets
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 23 of 64.
A farm game grows carrots and pumpkins. A carrot grows for 30 seconds and sells for 5 coins, a pumpkin grows for 90 seconds and sells for 40. Those numbers belong to the crop, not to one plant: as Inspector fields on a Plant script, every carrot in every scene holds its own copy of 30 and 5, and a change means finding all of them. A ScriptableObject keeps data like this in an asset, a file in the project that any number of objects can point at. Its class derives from ScriptableObject instead of MonoBehaviour:
using UnityEngine;
[CreateAssetMenu(fileName = "NewPlant", menuName = "Farm/Plant Data")]
public class PlantData : ScriptableObject
{
public string plantName;
public float growTime;
public int sellPrice;
}[CreateAssetMenu] puts the class in the Project window's Create menu. Right-click in the Project window, choose Create > Farm > Plant Data, and Unity makes an asset named NewPlant; rename it Carrot, select it, and type Carrot, 30 and 5 into its fields in the Inspector. A Pumpkin asset is made the same way. The class goes in a file named after it, PlantData.cs, as a MonoBehaviour does.
The behaviour stays in a MonoBehaviour with a field of the asset's type. Drag the Carrot asset onto that field, and the script reads the numbers through it:
public class Plant : MonoBehaviour
{
public PlantData data;
private float age;
void Update()
{
age += Time.deltaTime;
if (age >= data.growTime)
{
Debug.Log(data.plantName + " is ready, worth " + data.sellPrice);
enabled = false;
}
}
}A ScriptableObject is on no GameObject and in no scene. It has no Transform, and Unity never calls its Update or Start: it holds data, and the Plant holds the behaviour. When 200 carrots point at the one Carrot asset, setting its growTime to 25 changes all 200. In code, an instance is made with ScriptableObject.CreateInstance<PlantData>(), never with new.
Challenge
MediumMove the hero's settings into a data asset.
- In
HeroData.cs, writepublic class HeroData : ScriptableObjectwith publicstring heroName,float moveSpeedandColor color. - Put
[CreateAssetMenu(menuName = "Heroes/Hero Data")]on the line above it. - In
Hero.cs, replace the three fields withpublic HeroData data;and readdata.heroName,data.moveSpeedanddata.colorinstead.
Press Play: the red Knight walks at speed 3. Then Check.
Try it yourself
using UnityEngine;
// HeroData: the hero's name, speed and color, as a ScriptableObject
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular TurretRecap: Twin Cannon4Serialized Data
Serializable ClassesLists in the InspectorEnums in the InspectorRecap: Loot TableRecap: Roll the Loot2Interfaces in Unity
IDamageableInterfaces and TryGetComponentGetComponentsRecap: Interact KeyRecap: Nearest in Reach5ScriptableObjects
Data AssetsWeapon StatsShared SettingsSave the WindWaves as DataRecap: Item DatabaseRecap: Buy from the ShopPractice on your own: Unity playground