序列化 interface

首先,我们知道 Unity Inspector 是不可以序列化 interface 和 property 的。这确实也是个伪标题。此处介绍一种方法去检查是否带有此接口。

背景介绍:最近在写自己的求职 demo,其中我有一个 IGun 嘛,我想在挂载 Gun 的物体的 Inspector 上暴露出一个 IGun 的地方来把物体拖拽上去。但是这个不能序列化啊。因此就有了如下的方法。直接上代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PlayerGun : MonoBehaviour
{
[SerializeField] private GunConfigSO gunConfig;
private IGun _gun;
private GameObject _currentGun;

// ...

#ifdef UNITY_EDITOR
private void OnValidate()
{
if (gunConfig != null)
{
var gun = gunConfig.gunPrefab.GetComponent<IGun>();
if (gun == null)
{
UnityEngine.Debug.LogError("提供的 gunConfig 没有实现 IGun 接口");
}
}
}
#endif

// ...
}

我们只需使用一个在 Inspector 里面可以序列化的类型,比如 GameObject,毕竟我们需要序列化的接口大部分情况也需要将实现其的脚本挂载到物体身上。因此此处我们只需要使用 GameObject 为载体,接着使用 GetComponent 验证一下即可。

OnValidate

接下来详细说一下代码。

对于其中的 OnValidate,此为一个 unity 回调函数,且仅限编辑器,因此此处使用 #ifdef UNITY_EDITOR 将其包围。这个函数会在以下场景被触发:

  • 在加载脚本时
  • 在 Inspector 中更改值时
  • 加载场景时(在 OnEnable 之后,Start 之前调用)
  • 进入 Play Mode 时

此方法应该是仅限验证 Inspector 中修改的值,将其保证在特定范围之内。不应该使用其执行其它任务(如创建对象或调用其他非线程安全的 Unity API)