unity timeline bindings的存取和读入

Timeline的timelineAsset文件只会保留轨道的编辑信息,而不会保存轨道的绑定列表,这些绑定的信息是和场景一同绑定的。

unity timeline bindings的存取和读入_第1张图片

如果我们在制作的过程中没有保存场景,或者在协作的过程中只传送了timelineAsset而没有传送场景信息,这些绑定信息就会丢失,就像如下这种情况:

unity timeline bindings的存取和读入_第2张图片unity timeline bindings的存取和读入_第3张图片

 

我们可以通过创建Asset文件来保存和恢复绑定信息,具体思路是创建Asset来存储每个轨道绑定物体的名称,通过实现函数将名称信息保存到Asset文件里,在恢复的时候再通过读取Asset文件,根据其中存取的名称来恢复轨道的绑定。

 

Asset的创建:

unity timeline bindings的存取和读入_第4张图片

 

这一步非常简单,就是定义一个类,继承自ScriptableObject即可,当然,我们可以为这个类添加CreateMenu,以便于直接创建,但是这里我们没有太大的必要。

unity timeline bindings的存取和读入_第5张图片

Bindings信息存储:

        List bindingnames;

        PlayableDirector playableDirector = GameObject.FindGameObjectWithTag("director").GetComponent();

        bindingnames = new List();
        //获取timelineAsset中所有轨道的迭代器
        var bindings = playableDirector.playableAsset.outputs.GetEnumerator();
        //复制轨道中的对象名称

        while (bindings.MoveNext())
        {
            //获取当前轨道的绑定键
            Object sourceObject = bindings.Current.sourceObject;
            string bindingname;
            //根据绑定键获取当前轨道绑定物体的名称
            if (playableDirector.GetGenericBinding(sourceObject))
            {
                bindingname = playableDirector.GetGenericBinding(sourceObject).name;
            }
            else
                bindingname = "";
            bindingnames.Add(bindingname);
        }

 

bindings.Current.sourceObject充当绑定键的作用,timeline通过游戏对象和绑定键来绑定Binding信息,该绑定键由timelineAsset中的当前轨道来确定。通过获取每一个轨道的绑定键,再通过绑定键来获得绑定物体的名称,这些物体的名称就是我们要存取的信息。之后我们创建BindingAsset文件,根据这些信息来初始化文件:

        //实例化类

        BindingAsset bindingAsset = ScriptableObject.CreateInstance();
        //赋初值
        bindingAsset.playableName = new string[bindingnames.Count];

        for (int i = 0; i < bindingnames.Count; i++)
        {
            bindingAsset.playableName[i] = bindingnames[i];
        }

Bindings信息恢复:

        PlayableDirector playableDirector = GameObject.FindGameObjectWithTag("director").GetComponent();

        string path = string.Format("Assets/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;
            //通过名称找到需要绑定的物体
            GameObject gameObject = FindObject2(bindingAsset.playableName[i]);
            //通过绑定键和绑定物体的键值对,绑定Binding信息
            playableDirector.SetGenericBinding(sourceObject,
                gameObject);
            i++;
        }

 

即先根据名称找到要绑定的物体,然后用playableDirector.SetGenericBinding方法,将键值对进行绑定。其中,寻找物体的方法如下:


   

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;
}

关于这种寻找方法,可以参照我的另一篇博客:https://blog.csdn.net/weixin_43347688/article/details/107322746

 

知道了怎么存储和恢复,我们还要能够把这些信息保存起来,这个不用多解释了,代码如下

        //自定义资源保存路径
        string path = Application.dataPath + "/BindingAssets";

        //如果项目不包含该路径,创建一个
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
        path = string.Format("Assets/BindingAssets/{0}.asset", playableDirector.playableAsset.name);

        //生成自定义资源到指定路径
        AssetDatabase.CreateAsset(bindingAsset, path);

最后,贴一下完整的代码:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using System.IO;
using UnityEditor;

public class BindingOperator : MonoBehaviour
{
    /// 
    /// 将当前timeline中的对象名称存储到asset中
    /// 
    [MenuItem("TimelineTools/存储timeline绑定 %_i")]
    private static void Fork()
    {
        List bindingnames;

        PlayableDirector playableDirector = GameObject.FindGameObjectWithTag("director").GetComponent();

        bindingnames = new List();

        //获取timelineAsset中所有轨道的迭代器
        var bindings = playableDirector.playableAsset.outputs.GetEnumerator();

        //复制轨道中的对象名称
        while (bindings.MoveNext())
        {
            //获取当前轨道的绑定键
            Object sourceObject = bindings.Current.sourceObject;

            string bindingname;

            //根据绑定键获取当前轨道绑定物体的名称
            if (playableDirector.GetGenericBinding(sourceObject))
            {
                bindingname = playableDirector.GetGenericBinding(sourceObject).name;
            }
            else
                bindingname = "";
            bindingnames.Add(bindingname);
        }

        string path0 = string.Format("Assets/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 = new string[bindingnames.Count];

        for (int i = 0; i < bindingnames.Count; i++)
        {
            bindingAsset.playableName[i] = bindingnames[i];
        }
        //如果实例化为空,返回
        if (!bindingAsset)
        {
            Debug.LogWarning("bindingAsset not found");
            return;
        }
        //自定义资源保存路径
        string path = Application.dataPath + "/BindingAssets";

        //如果项目不包含该路径,创建一个
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        path = string.Format("Assets/BindingAssets/{0}.asset", playableDirector.playableAsset.name);

        //生成自定义资源到指定路径
        AssetDatabase.CreateAsset(bindingAsset, path);
    }

    /// 
    /// 利用asset中存储的名称恢复timeline的对象
    /// 
    ///
    [MenuItem("TimelineTools/恢复timeline绑定 %_k")]
    private static void Restore()
    {
        PlayableDirector playableDirector = GameObject.FindGameObjectWithTag("director").GetComponent();

        string path = string.Format("Assets/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;

            //通过名称找到需要绑定的物体
            GameObject gameObject = FindObject2(bindingAsset.playableName[i]);

            //通过绑定键和绑定物体的键值对,绑定Binding信息
            playableDirector.SetGenericBinding(sourceObject,
                gameObject);

            i++;
        }
    }

    //根据名称在hierarchy里找到物体,包括隐藏的物体
    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;
    }
}

 

你可能感兴趣的:(Unity)