可序列化类
本课属于 Coddy Unity 学习旅程的“Unity 游戏架构”单元。第 18 课,共 64 课。
设置很多的脚本会在 Inspector 中显示一长串扁平列表。普通的 C# 类可以把这些设置分组:为它标记 [System.Serializable],该类的字段就会显示为一个折叠面板,面板以字段命名,里面包含这个类的各个字段。一个类可以供多个字段和多个脚本使用:
[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;
}
}Inspector 会显示两个折叠面板,Normal 和 Enraged,每个面板都有 Speed 和 Damage。每个 Enemy 都有自己的两个 Stats 对象,并在自己的 Inspector 中填写这些对象的值,代码通过 normal.speed 来读取它们。Unity 加载脚本时会创建这些对象,因此即使没有 = new Stats(),normal 也永远不会是 null;字段初始化器(2 和 10)就是新 Enemy 的初始值。结构体也可以用同样的特性,[System.Serializable] public struct Range { public float min; public float max; },并且像 Vector3 一样,在赋值时会被复制。
需要这个特性,是因为 Unity 只会保存它被告知要保存的类型。没有它,这个类在 Inspector 中不可见:没有折叠面板,在 Inspector 中设置的值不会被保存,Unity 也不会创建对象,所以 normal.speed 会抛出 NullReferenceException。在类内部,通常的 Inspector 规则仍然适用:使用 public 字段或带有 [SerializeField] 的 private 字段,不能使用属性或静态字段。
挑战
简单将每个光束的设置归到一个结构体中。
- 在
Flashlight上方,声明public struct Beam,其中包含公共的Color color、float range和float angle。添加[System.Serializable],这样 Inspector 中就会显示它。 - 将六个分散的字段替换为
public Beam wide;和public Beam focused;。 - 在
Apply()中,根据focusedOn ? focused : wide设置灯光的三个值。
按“开始”,然后按 Space:光束就能照到水晶。然后点击“检查”。
亲手试试
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;
}
}
Unity 游戏架构中的所有课
自己练习: Unity 在线编辑器