Timeline的资源是.playable文件,简单的复制不会保留引用关系。
下面的脚本可以复制引用关系。
csharp
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using UnityEditor;
public class CopyTimeline : MonoBehaviour
{
[MenuItem("JFrameWork/Resources/克隆 Timeline", true)]
private static bool DupTimelineValidate()
{
if (!(Selection.activeObject is GameObject playableDirectorObj))
{
Debug.Log("Null active object");
return false;
}
var playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
if (playableDirector == null)
{
Debug.Log("Null playableDirector");
return false;
}
var timelineAsset = playableDirector.playableAsset as TimelineAsset;
if (timelineAsset == null)
{
Debug.Log("Null timelineAsset");
return false;
}
var path = AssetDatabase.GetAssetPath(timelineAsset);
if (string.IsNullOrEmpty(path))
{
Debug.Log("Null timeline asset path");
return false;
}
return true;
}
[MenuItem("JFrameWork/Resources/克隆 Timeline")]
public static void DupTimeline()
{
if (!(Selection.activeObject is GameObject playableDirectorObj))
{
Debug.LogError("Invalid selection. Please select a GameObject with a PlayableDirector.");
return;
}
var playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
if (playableDirector == null)
{
Debug.LogError("No PlayableDirector component found on the selected GameObject.");
return;
}
var timelineAsset = playableDirector.playableAsset as TimelineAsset;
if (timelineAsset == null)
{
Debug.LogError("Selected GameObject does not have a TimelineAsset.");
return;
}
var path = AssetDatabase.GetAssetPath(timelineAsset);
var newPath = path.Replace(".playable", "(Clone).playable");
if (!AssetDatabase.CopyAsset(path, newPath))
{
Debug.LogError("Couldn't clone asset.");
return;
}
// Copy Bindings
var newTimelineAsset = AssetDatabase.LoadMainAssetAtPath(newPath) as TimelineAsset;
if (newTimelineAsset == null)
{
Debug.LogError("Failed to load cloned timeline asset.");
return;
}
var oldBindings = timelineAsset.outputs.ToArray();
var newBindings = newTimelineAsset.outputs.ToArray();
for (int i = 0; i < oldBindings.Length; i++)
{
playableDirector.playableAsset = timelineAsset;
var boundTo = playableDirector.GetGenericBinding(oldBindings[i].sourceObject);
playableDirector.playableAsset = newTimelineAsset;
playableDirector.SetGenericBinding(newBindings[i].sourceObject, boundTo);
}
// Copy Exposed References
playableDirector.playableAsset = newTimelineAsset;
foreach (var newTrackAsset in newTimelineAsset.GetRootTracks())
{
foreach (var newClip in newTrackAsset.GetClips())
{
foreach (var fieldInfo in newClip.asset.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
if (fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(ExposedReference<>))
{
var exposedReference = fieldInfo.GetValue(newClip.asset);
var oldExposedName = (PropertyName)fieldInfo.FieldType.GetField("exposedName").GetValue(exposedReference);
// Fetch Old Exposed Value
if (!playableDirector.GetReferenceValue(oldExposedName, out bool isValid))
{
Debug.LogError("Failed to copy exposed references. Could not find: " + oldExposedName);
return;
}
var oldExposedValue = playableDirector.GetReferenceValue(oldExposedName, out isValid);
// Replace exposedName on struct
var newExposedName = new PropertyName(GUID.Generate().ToString());
fieldInfo.FieldType.GetField("exposedName").SetValue(exposedReference, newExposedName);
// Set ExposedReference
fieldInfo.SetValue(newClip.asset, exposedReference);
// Set Reference on Playable Director
playableDirector.SetReferenceValue(newExposedName, oldExposedValue);
}
}
}
}
Debug.Log("Timeline duplicated successfully.");
}
}
我们选中PlayableDirector对象,然后点击克隆Timeline菜单,就直接复制了。
然后我们可以把TL1复制一份,这样就2个Timeline都有引用关系了。
到这里就结束了。