Unity拷贝预制体和Playable资源,并恢复PlayableDirector丢失的Bindings数据

文章描述了在Unity中,如何在复制预制体时确保新的Prefab引用的新Playable资源,并保持PlayableDirector的Bindings信息不丢失。方法包括复制Playable资源、恢复Bindings数据并进行适配。
摘要由CSDN通过智能技术生成

问题

由于预制体和Playable资源分开存放, 当需要拷贝一份新资源重新编辑时, 新的预制体绑定的Playable仍是旧资源, 且手动替换到新资源后, PlayableDirector上的Bindings信息会丢失

  • 拷贝后, 新预制体的Playable仍引用旧资源
    拷贝后, 新预制体的Playable仍引用旧资源

  • 手动替换Playable资源后, Bindings丢失
    手动替换Playable资源后, Bindings丢失

目标

  • 使拷贝后的预制体, Playable引用新资源
  • PlayableDirector的Bindings信息不丢失

代码

/// <summary>
/// 拷贝资源
/// </summary>
/// <param name="originPath"></param>
/// <param name="copyToPath"></param>
public static async void CopyAsset(string originPath, string copyToPath)
{
    if (!AssetDatabase.CopyAsset(originPath, copyToPath))
    {
        Debug.LogError("拷贝失败");
        return;
    }

    var originPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(originPath);
    if (originPrefab.TryGetComponent<PlayableDirector>(out var originDirector))
    {
        var newPlayablePath = GetPlayableAssetPath(copyToPath);
        var originPlayablePath = AssetDatabase.GetAssetPath(originDirector.playableAsset);

        if (!AssetDatabase.CopyAsset(originPlayablePath, newPlayablePath))
        {
            Debug.LogError("拷贝失败");
            return;
        }

        var copyPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(copyToPath);
        var copyDirector = copyPrefab.GetComponent<PlayableDirector>();

        // 新预制体绑定新Playable资源
        copyDirector.playableAsset = AssetDatabase.LoadAssetAtPath<TimelineAsset>(newPlayablePath);
        copyDirector.playableAsset.name = System.IO.Path.GetFileNameWithoutExtension(newPlayablePath);

        // 恢复拷贝的Playable资源的bindings信息
        var directorSO = new SerializedObject(copyDirector);
        var sceneBindings = directorSO.FindProperty("m_SceneBindings");

        // 等一帧加载
        newDirector.Play();
        await UniTask.NextFrame();

        // 删除PlayableDirector.Bindgings的空Key项, 并把原Timeline文件的轨道Key替换到当前Timeline文件的轨道对象
        var bindingsKv = new Dictionary<Object, Object>();
        for (var i = 0; i < sceneBindings.arraySize; i++)
        {
            var bindingElement = sceneBindings.GetArrayElementAtIndex(i);
            // key是源文件的轨道对象,value是当前文件的绑定value
            var key = bindingElement.FindPropertyRelative("key").objectReferenceValue;
            var val = bindingElement.FindPropertyRelative("value").objectReferenceValue;

            if (key == null)
            {
                continue;
            }
            bindingsKv.Add(key, val);
        }

        // 移除无用的绑定
        while (sceneBindings.arraySize > 0)
        {
            sceneBindings.DeleteArrayElementAtIndex(0);
        }
        directorSO.ApplyModifiedProperties();

        // 设置有效绑定
        foreach (var kv in bindingsKv)
        {
            copyDirector.SetGenericBinding(kv.Key, kv.Value);
        }

        // 设置有效绑定 (新老timeline资源outputs顺序完全一致)
        var lstout = director.playableAsset.outputs.ToList();
        var newout = newDirector.playableAsset.outputs.ToList();
        for (int i = 0; i < lstout.Count; i++)
        {
            var lstTrack = lstout[i].sourceObject as TrackAsset;
            var newTrack = newout[i].sourceObject as TrackAsset;

            if (bindingsKv.ContainsKey(lstTrack))
            {
                newDirector.SetGenericBinding(newTrack, bindingsKv[lstTrack]);
            }
        }

        AssetDatabase.SaveAssetIfDirty(copyPrefab);
    }
}

/// <summary>
/// 获取PlayableAsset路径
/// Playable资源和Prefab资源在同一目录下
/// </summary>
/// <param name="savePath"></param>
/// <returns></returns>
private static string GetPlayableAssetPath(string savePath)
{
    var prefabName = System.IO.Path.GetFileName(savePath);
    var timelineName = System.IO.Path.GetFileNameWithoutExtension(prefabName) + ".playable";
    var timelineSavePath = savePath.Replace(prefabName, "").Replace(Application.dataPath, "");
    if (timelineSavePath.StartsWith("Assets"))
    {
        return timelineSavePath + timelineName;
    }
    return "Assets" + timelineSavePath + timelineName;
}
  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 在Unity中,雨天场景是一个很常见的场景,为了方便制作,我们可以使用预制来创建雨天效果。预制是一种Unity中的可复用资源,它保存了一组游戏对象,可以在需要的时候进行实例化使用。 首先,我们需要创建一个雨滴的模型作为游戏对象,并将其设置为粒子系统,使用粒子效果创建出水滴下落的效果。这个模型需要设置一些参数,如颜色、速度、数量、大小等,以让雨滴的效果更加逼真。 接着,我们需要将这个雨滴模型设置为预制。在预制模式下添加预制,将雨滴模型加入到预制中,并保存预制。这样我们就可以在其他场景或其他项目中使用这个雨滴预制了。 在使用预制时,我们可以直接拖拽雨滴预制到场景中即可创建出雨滴效果,并根据需要调整一些参数,如场景中的雨滴数量、掉落的速度等。 总之,利用Unity中的预制,我们可以非常方便地创建出雨天效果,提高我们的游戏开发效率。 ### 回答2: Unity 中的雨预制可以用于创建逼真的雨水效果,为游戏界面增添一些真实感。其中,预制是一个可以预先设置属性的对象,方便在游戏中进行调用。使用雨预制,我们可以设置雨滴大小、密度等参数,还可以为雨水添加音效、粒子效果等,增添更多的交互和视觉效果。 为了创建雨预制,在 Unity资源目录中新建一个 Particle Systems,调整参数使其模拟雨滴的运动轨迹和外观,添加声音和效果后进行组合,形成一个完整的雨预制。 有了雨预制后,我们就可以在游戏中使用它,通过脚本进行调用来实现各种雨滴效果。比如,在某个场景中加载雨预制,使得场景中出现逼真的雨滴效果,为游戏增添一定的视觉效果。 总的来说,Unity 的雨预制是游戏开发中不可缺少的一部分。它可以增加游戏的逼真感,同时也能帮助开发者快速创建雨水效果,是游戏开发中不可缺少的利器。 ### 回答3: Unity 是一款非常强大的游戏引擎,可以用于开发各种类型的游戏。其中,雨效果是游戏中常见的特效之一,可以增强游戏的真实感和沉浸感。为了便于开发者使用,Unity 提供了下雨预制,可以直接在游戏中使用。 下雨预制包括多个元素,例如雨滴、水珠、云层等。使用者可以自由调整这些元素的样式、数量、速度、密度等参数,以实现不同的雨效果。此外,预制还提供了丰富的动画效果,例如雨滴落地时的溅开效果、雨滴在物表面的流动效果等。 在使用下雨预制时,开发者只需将其拖拽到场景中即可。可以自行调整预制在场景中的位置和大小,以适应不同的场景需求。同时,开发者还可以通过代码实现更精细的雨效果,例如调整雨滴的颜色、透明度、大小等。 总之,Unity 下雨预制是游戏开发中非常实用的一种特效资源,可以帮助开发者快速、方便地创建出逼真的雨效果,提升游戏的质量和观赏度。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值