通过脚本使用 Cross-Scene Reference
在直接进入如何通过 C# 访问 Cross-Scene Reference 之前,我们先来熟悉一下如何在 Command 中使用 CommandGUI 绘制一个 Target Field。
我们将创建一个 Command,用来打印 Target Field 中指定的 GameObject 的名称。
打开 Assets 菜单,选择 Create -> Sequine -> C# Command Script,创建一个新的 Command 脚本。将文件命名为 LogGameObjectCommand(可选)。
创建 Target Field
要创建一个 Target Field,首先需要声明一个 public 的 TargetObject<T> 字段,用于存储引用,其中 T 是我们希望指向的 Object 类型。
要在 Command 中绘制 Target Field,可以调用 CommandGUI.DrawTargetObjectField 方法。如果你已经阅读过 自定义 Command 类型,那么应该已经熟悉它的参数了。
正如在 跨场景系统 中所解释的那样,一个 Target Field 有三种不同的方式来 赋值 实际的 Object。但无论使用哪一种方式进行赋值,在需要 获取 实际 Object 时,都可以通过调用 GetObject 方法来完成。
...
[System.Serializable]
[RegisterCommand("Custom/Log GameObject", typeof(SequineFlowCommandData))]
public class LogGameObjectCommand : Command {
public override float nodeWidth => 300;
public TargetObject<GameObject> gameObjectToLog;
public override void Execute(CommandExecutionFlow _flow) {
if (gameObjectToLog != null) {
var value_gameObjectToLog = gameObjectToLog.GetObject();
if (value_gameObjectToLog != null) {
Debug.Log("The name is: " + value_gameObjectToLog.name);
}
}
Exit();
}
#if UNITY_EDITOR
public override void Editor_OnDrawContents(Vector2 _absPosition) {
CommandGUI.DrawTargetObjectField("GameObject to Log", ref gameObjectToLog);
}
#endif
}

到目前为止,我们应该已经可以把层级视图中的 GameObject 直接设置到 GameObject to Log 字段中了。
运行测试
现在尝试指定目标并运行。

在 MonoBehaviour / ScriptableObject 中使用 Target Field
在 Command 中,TargetObject<T> 提供了 3 种不同的目标指定方式,这是为了减少可用 Command 的冗余。试想一下,如果 Sequine 为每一种方式都提供一个独立的 Command,那么每个 Command 类型都需要被复制成 3 份。因此,我们把它们整合为同一个 Command 中的下拉选项。
但是,如果我们是在 MonoBehaviour 或 ScriptableObject 中指定目标,就没有必要再使用这样的下拉结构。
如果我们想要 指定 Direct Object,那么只需像平时一样声明一个 public 或可序列化字段 即可。
如果我们想要 通过 Legacy Cross-Scene Binder 指定目标,同样可以声明一个 public 或可序列化字段,只不过字段类型需要是对应的 binder asset 类型。可以阅读 通过脚本使用 Cross-Scene Binding(Legacy)。
而如果我们希望使用 Cross-Scene Reference 指定目标,那么就不再声明 Object 类型字段,而是声明一个 GUID 字段,具体来说是 SerializableGUID。为了让它可以在 Inspector 中编辑,需要添加 [CrossSceneRef] 特性。
我们还可以在 CrossSceneRef 特性中传入一个 System.Type 参数,用来指定目标对象的类型。
using UnityEngine;
using Calcatz.CookieCutter;
public class CrossSceneRefExample : MonoBehaviour {
[CrossSceneRef(typeof(MeshRenderer))]
public SerializableGUID meshRendererTarget;
}

在运行时,如果需要访问该对象,可以使用 CrossSceneRefsUtility.GetObject 方法,并在参数中传入对应的 GUID。
...
public class CrossSceneRefExample : MonoBehaviour {
[CrossSceneRef(typeof(MeshRenderer))]
public SerializableGUID meshRendererTarget;
private void Start() {
var meshRendererObject = CrossSceneRefsUtility.GetObject(meshRendererTarget);
Debug.Log(meshRendererObject.name);
}
}
手动将组件标记为 Cross-Scene
跨场景对象引用会被存储在一个字典中。
在后台,当我们通过拖拽的方式进行赋值时,希奎引会自动把该对象加入为跨场景对象。
虽然拖拽非常方便,但我们同样可以通过右键点击组件,手动将对象添加到或从跨场景对象注册表中移除。
