在 Unity 中,ExposedReference<T> 是一个特殊的泛型结构,主要用于 解决序列化引用时的上下文问题,特别是在 Timeline 动画系统 和 Playables API 中。它的核心功能是允许你在编辑器中配置一个引用,但实际解析(获取目标对象)推迟到运行时完成。

由于 Unity 的 Asset 只能引用资源对象,不能引用场景中的对象。所以 Unity 提供 ExposedReference 和 IExposedPropertyTable 机制来实现 Asset 引用场景中的对象

一般来说ExposedReference字段只能通过在场景中拖拽的方式赋值,但如果片段比较多的话一个一个拖会很麻烦,这时候可以写个编辑器扩展,根据自己的需要在场景中找到对应的物体,再给ExposedReference<T> 类型的字段赋值就行了,具体代码如下,注释写的很详细,用法也很简单,这里以timeline为例,_director是一个PlayableDirector类型的对象,把需要的参数传进去就行了

    /// <summary>
    /// 给PlayableDirector添加引用
    /// </summary>
    /// <param name="obj">场景中的物体</param>
    /// <param name="sayText">自定义轨道资源脚本</param>
    private void AddExposedReference(Object obj, SayTextPlayableAsset sayText)
    {
        // 生成一个唯一的标识符,用于标识特定的对象或资源
        var guid = GUID.Generate().ToString();
        
        // 将生成的唯一标识符与对象关联,以便在后续操作中可以引用或管理该对象
        _director.SetReferenceValue(guid, obj);
        
        AddExposedReference(guid, sayText);
    }

    /// <summary>
    /// 将引用的键存到ExposedReference字段类型的容器中,并持久化保存
    /// </summary>
    /// <param name="guid"></param>
    /// <param name="sayText">自定义轨道资源脚本</param>
    private void AddExposedReference(string guid, SayTextPlayableAsset sayText)
    { 
        // 创建一个SerializedObject实例,用于序列化sayText对象
        var cloneObject = new SerializedObject(sayText);

        // 获取cloneObject的属性迭代器
        SerializedProperty prop = cloneObject.GetIterator();

        // 遍历所有属性
        while (prop.Next(true))
        {
            // 检查当前属性是否为暴露引用类型
            if (prop.propertyType == SerializedPropertyType.ExposedReference)
            {
                // 找到当前属性的exposedName属性
                var exposedNameProp = prop.FindPropertyRelative("exposedName");

                // 将exposedName属性的字符串值设置为guid
                exposedNameProp.stringValue = guid;
            }
        }

        // 应用修改到属性,不记录撤销信息
        cloneObject.ApplyModifiedPropertiesWithoutUndo();
    }

更多推荐