Serializable Classes
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 15 of 50.
A script with many settings gets a long, flat list in the Inspector. A plain C# class can group them: mark it [System.Serializable], and a field of that class shows as a foldout named after the field, with the class's fields inside. One class can serve several fields and several scripts:
[System.Serializable]
public class Stats
{
public float speed = 2f;
public int damage = 10;
}
public class Enemy : MonoBehaviour
{
public Stats normal;
public Stats enraged;
private Stats current;
void Start()
{
current = normal;
}
void Update()
{
transform.Translate(0f, 0f, current.speed * Time.deltaTime);
}
public void Enrage()
{
current = enraged;
}
}The Inspector shows two foldouts, Normal and Enraged, each with a Speed and a Damage. Every Enemy gets its own two Stats objects, filled in its own Inspector, and code reads them as normal.speed. Unity creates these objects when it loads the script, so normal is never null even without = new Stats(), and the field initializers (2 and 10) are what a new Enemy starts with. A struct works the same way with the attribute, [System.Serializable] public struct Range { public float min; public float max; }, and like Vector3 it is copied when it is assigned.
The attribute is needed because Unity saves only the types it is told to. Without it the class is invisible to the Inspector: there is no foldout, values set there are not saved, and Unity does not create the object, so normal.speed throws a NullReferenceException. Inside the class the usual Inspector rules hold: public fields or [SerializeField] private ones, never properties or static fields.
Challenge
EasyThe explorer's flashlight has two beams, and Space switches between them: a wide, warm beam for looking around and a focused, cool white one that reaches deep into the cave. Flashlight.cs keeps each beam's three settings in six loose fields. The scene is already set up with the settings grouped per beam, and the script has to match it:
- Declare a struct
Beamwith three public fields:color(a Color),rangeandangle(floats). The Inspector must show it. - Replace the six loose fields with two Beam fields,
wideandfocused. The scene sets wide to a warm color, range 6 and angle 80, and focused to a cool white, range 15 and angle 25. - Make
Apply()read the current beam's Beam and set the Light'scolor,rangeandspotAnglefrom it. The rest stays: the flashlight starts with the wide beam, and Space switches beams.
Press Play, press Space to light up the far end of the cave, then Check.
Try it yourself
using UnityEngine;
using UnityEngine.InputSystem;
public class Flashlight : MonoBehaviour
{
public Color wideColor = Color.white;
public float wideRange = 5f;
public float wideAngle = 60f;
public Color focusedColor = Color.white;
public float focusedRange = 10f;
public float focusedAngle = 30f;
private bool focusedOn;
private Light lamp;
void Start()
{
lamp = GetComponent<Light>();
Apply();
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
focusedOn = !focusedOn;
Apply();
}
}
void Apply()
{
lamp.color = focusedOn ? focusedColor : wideColor;
lamp.range = focusedOn ? focusedRange : wideRange;
lamp.spotAngle = focusedOn ? focusedAngle : wideAngle;
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular Turret10Project: Arena Survivor
The HeroEnemy Types