这个特性源自Unity2019.3版本的更新上,在版本发行的说明上,只有简短的一行!但是开发者对于此特性的讨论是连绵不绝的。
我一度认为这个升级,比其它的新的功能或者升级的功能的价值都要高。最直观的就是,当你想写一套完整的FSM框架时,这个特性将你的成本缩短到以前的1/10,甚至更多!
多态
多态这个特性,在序列化这一块一直都是头疼的问题,还是拿FSM来举例吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[Serializable] public class FsmState { [SerializeReference] private List<FsmStateAction> actions = new List<FsmStateAction>(); } public class FsmStateAction { ... } public class WaitAction : FsmStateAction { ... } public class PlayAction : FsmStateAction { ... } //添加到字段里 fsmState.actions.Add(new WaitAction()); fsmState.actions.Add(new PlayAction()); |
如上所示,actions会根据不同类型的Action而显示在Inspector中。
好处:
- 不用为每个Action单独的写Inspector类
- 不用单独写一份保存Action的数据逻辑 (之前通常为穷举所有数据类型,或者自定义解析/反解析字符串)
- 不用单独写一分序列化数据的逻辑(之前通常是反射)
引用
之前的做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Fsm { [SerializeField] private string startStateName; [SerializeField] private FsmState[] allStates; private FsmState startState; private FsmState GetState(string name) { ... } public void Init() { startState = GetState(startStateName); } } |
现在的做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Fsm { // <s>public string startStateName;</s> [SerializeReference] private FsmState[] allStates; [SerializeReference] private FsmState startState; private FsmState GetState(string name) { ... } public void Init() { // <s>startState = GetState(startStateName);</s> } } |
好处:
- 当修改State名字时,不必恐慌你所引用的StateName没有更新。
- 不需要再去寻找State,编辑器通过引用已经帮你实例。
下面也来说说SerializeReference的其它信息:
- 好的:数据量自动优化,我尝试过在编辑器实例化100个引用字段出来,但是最终没有任务地方引用它们,当你以Text形式打开你的.prefab文件,你会发现,没有引用的字段全被干掉了。
- 好的:所以的引用字段都以一个单独的id的形式,所以不会产生两个引用使用同一个id时产生数据的冗余。
- 坏的:你必须写一套编辑器代码来对你带有SerializeReference进行添加与删除。
- 坏的:如果你改了类名,引用将丢失。(你可以通过手改Prefab文件里面引用名来实现对应,这样的话,工作量就大了)