恢复丢失的timeline绑定数据
在使用Timline的过程中 经常会发生 绑定的信息丢失了的情况。一般交付给我们的资源是美术制作好的timeline 动画 我们并不知道 绑定的节点对应物体。所以非常有必要。做一个绑定数据的记录工具。而且我们也需要对资源打包处理 ,在把资源做成AB包时 ,场景中的绑定信息也会丢失。这时就需要我们要动态的加载绑定信息。上代码。
TimeLineWinEditor :
主要负责创建 记录文件的。代码比较简单。直接看就行了。
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
public class TimeLineWinEditor : EditorWindow
{
public static PlayableDirector playableDirector;
void OnGUI()
{
playableDirector = EditorGUILayout.ObjectField(playableDirector, typeof(PlayableDirector), true) as PlayableDirector;
if (GUILayout.Button("创建TimeLine记忆文件"))
{
Fork();
}
if (GUILayout.Button("读取TimeLine记忆文件"))
{
Restore();
}
}
//[MenuItem("TimelineTools/存储timeline绑定 %_i")]
private static void Fork()
{
List bindingnames_Game;
List bindingnames_Editor;
bindingnames_Editor = new List();
bindingnames_Game = new List();
//获取timelineAsset中所有轨道的迭代器
var bindings = playableDirector.playableAsset.outputs.GetEnumerator();
//复制轨道中的对象名称
while (bindings.MoveNext())
{
//获取当前轨道的绑定键
Object sourceObject = bindings.Current.sourceObject;
string bindingname_Editor;
string bindingname_Game;
//根据绑定键获取当前轨道绑定物体的名称
if (sourceObject != null)
{
if (playableDirector.GetGenericBinding(sourceObject))
{
Object obj1 = playableDirector.GetGenericBinding(sourceObject);
GameObject go = obj1 as GameObject;
if (go == null)
{
Animator animaotr = obj1 as Animator;
if (animaotr == null)
{
AudioSource audioSource = obj1 as AudioSource;
go = audioSource.gameObject;
}
else
{
go = animaotr.gameObject;
}
}
List gameObjectNames = new List();
while (go && go.name != null && go.name != "Point light")
{
gameObjectNames.Add(go.name);
if (go.transform.parent != null)
{
go = go.gameObject.transform.parent.gameObject;
}
else
{
go = null;
}
}
gameObjectNames.RemoveAt(gameObjectNames.Count - 1);
gameObjectNames.Reverse();
string path1 = null;
foreach (string str in gameObjectNames)
{
path1 += str;
path1 += "/";
}
if (path1 != null)
{
if (path1.Length > 0)
{
path1 = path1.Substring(0, path1.Length - 1);
}
}
Debug.Log(path1);
bindingname_Editor = playableDirector.GetGenericBinding(sourceObject).name;
bindingname_Game = path1;
}
else
{
bindingname_Editor = "";
bindingname_Game = "";
Debug.Log(sourceObject + "null");
}
if (!string.IsNullOrEmpty(bindingname_Game))
{
bindingnames_Game.Add(bindingname_Game);
}
if (!string.IsNullOrEmpty(bindingname_Editor))
{
bindingnames_Editor.Add(bindingname_Editor);
}
}
}
string path0 = string.Format("Assets/Resources/BindingAssets/{0}.asset", playableDirector.playableAsset.name);
//如果已经存在有binding的绑定,则决定是否替换或者保留
if (File.Exists(path0))
{
if (EditorUtility.DisplayDialog("注意", "替换原来的binding?", "是", "否"))
{
File.Delete(path0);
}
else
return;
}
//实例化类
BindingAsset bindingAsset = ScriptableObject.CreateInstance();
//赋初值
bindingAsset.playableName_Game = new string[bindingnames_Game.Count];
bindingAsset.playableName_Editor = new string[bindingnames_Editor.Count];
for (int i = 0; i < bindingnames_Game.Count; i++)
{
bindingAsset.playableName_Game[i] = bindingnames_Game[i];
}
for (int i = 0; i < bindingnames_Editor.Count; i++)
{
bindingAsset.playableName_Editor[i] = bindingnames_Editor[i];
}
//如果实例化为空,返回
if (!bindingAsset)
{
Debug.LogWarning("bindingAsset not found");
return;
}
//自定义资源保存路径
string path = Application.dataPath + "/Resources/BindingAssets";
//如果项目不包含该路径,创建一个
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
path = string.Format("Assets/Resources/BindingAssets/{0}.asset", playableDirector.playableAsset.name);
AssetDatabase.CreateAsset(bindingAsset, path);
}
private static void Restore()
{
string path = string.Format("Assets/Resources/BindingAssets/{0}.asset", playableDirector.playableAsset.name);
if (!File.Exists(path))
return;
BindingAsset bindingAsset = AssetDatabase.LoadAssetAtPath(path);
//获取timelineAsset中所有轨道的迭代器
var bindings = playableDirector.playableAsset.outputs.GetEnumerator();
int i = 0;
//根据对象名称恢复timeline的轨道
while (bindings.MoveNext())
{
//获取当前轨道的绑定键
Object sourceObject = bindings.Current.sourceObject;
if (sourceObject != null)
{
//通过名称找到需要绑定的物体
GameObject gameObject = FindObject2(bindingAsset.playableName_Editor[i]);
//通过绑定键和绑定物体的键值对,绑定Binding信息
playableDirector.SetGenericBinding(sourceObject, gameObject);
i++;
}
}
}
private static GameObject FindObject2(string name)
{
foreach (GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)))
{
if (!EditorUtility.IsPersistent(go.transform.root.gameObject) && !(go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave))
{
if (go.name == name)
return go;
}
}
return null;
}
}
BindingAsset
记录信息的配置文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "BindingAsset", fileName = "bindingAsset", order = 2)]
public class BindingAsset : ScriptableObject
{
public string[] playableName_Editor;
public string[] playableName_Game;
}
AutoBindTimeLine
运行时自动绑定Timeline数据
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Playables;
public class AutoBindTimeLine : MonoBehaviour
{
public static AutoBindTimeLine instance;
public delegate void BindTimeLine(PlayableDirector playable);
public event BindTimeLine mBindTimeLine;
public PlayableDirector mPlayableDirector;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
mBindTimeLine += AutoBindTimeLine_onBindTimeLine;
}
public void OnBindTimeLine(PlayableDirector mPlayableDirector)
{
if (mBindTimeLine != null)
{
mBindTimeLine?.Invoke(mPlayableDirector);
}
}
private void AutoBindTimeLine_onBindTimeLine(PlayableDirector playable)
{
string path = string.Format("Assets/Resources/BindingAssets/{0}.asset", playable.playableAsset.name);
if (!File.Exists(path))
return;
BindingAsset bindingAsset = Resources.Load("BindingAssets/" + playable.playableAsset.name);
//获取timelineAsset中所有轨道的迭代器
var bindings = playable.playableAsset.outputs.GetEnumerator();
int i = 0;
//根据对象名称恢复timeline的轨道
while (bindings.MoveNext())
{
Debug.Log(i);
//获取当前轨道的绑定键
Object sourceObject = bindings.Current.sourceObject;
if (sourceObject != null)
{
Debug.Log(bindingAsset.playableName_Game[i]);
GameObject gameObject = transform.Find(bindingAsset.playableName_Game[i]).gameObject;
//通过绑定键和绑定物体的键值对,绑定Binding信息
playable.SetGenericBinding(sourceObject, gameObject);
i++;
}
}
}
}
我们的脚本AutoBindTimeLine 要挂在一个父节点上面才能find到下面的子物体。