2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Unity Timeline(Playable Director)を複製した際にGameObjectのバインドがはずれてしまう。。

2
Last updated at Posted at 2021-08-31

初めに

プロジェクト
Timeline(Playable Director)を複製した際にGameObjectのバインドがはずれてしまう。。

どんな現象かと言うと。

1.まず、適当にCubeが拡縮するアニメーション作ります。

time01.gif

2、同じようなシーンを作りたくて、シーンをコピーして複製したシーンを開きます。

time02.gif

3,複製元のTimeline(Playable Director)と同じになってしまうので、プロジェクトウィンドウでTimeline(Playable Director)も
コピーし複製先のシーンのTimeline(Playable Director)にアタッチすると1,で作ったアニメーションのGameObjectのバインドが外れてしまう。

time03.gif

Unity Forumsで 解決

意外とあっさり、同じことで悩んでいる方がいて、解決しました。

seant_unityさんが対策のスクリプト書いてくれてますが、Timeline(Playable Director)の複製を作って、、HierarchyにTimeline(Playable Director)のCloneをつくり、同じパスにTimeline(Playable Director)のオブジェクトもCloneを作ってくれるものでした。

そのあと、書き込みでも動作しないとか書き込みがあるので、割と最近の投稿のRibさんの投稿を採用することしました。

こんな感じ

やったのは、シーンを複製して複製先のシーンでTimeline(Playable Director)の複製を行っただけ

time04.gif

スクリプト

using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using UnityEditor;

public class DuplicateTimeline : EditorWindow
{
    [MenuItem("imeline/Duplicate Timeline", true)]
    private static bool DupTimelineValidate()
    {
        if (UnityEditor.Selection.activeObject as GameObject == null)
        {
            Debug.Log("Null active object");
            return false;
        }

        GameObject playableDirectorObj = UnityEditor.Selection.activeObject as GameObject;

        PlayableDirector playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
        if (playableDirector == null)
        {
            Debug.Log("Null playableDirector");
            return false;
        }

        TimelineAsset timelineAsset = playableDirector.playableAsset as TimelineAsset;
        if (timelineAsset == null)
        {
            Debug.Log("Null timelineAsset");
            return false;
        }

        string path = AssetDatabase.GetAssetPath(timelineAsset);
        if (string.IsNullOrEmpty(path))
        {
            Debug.Log("Null timeline asset path");
            return false;
        }

        return true;
    }

    [MenuItem("Timeline/Duplicate Timeline")]
    public static void DupTimeline()
    {
        // 再生可能なディレクターを取得し、タイムラインを取得します
        GameObject playableDirectorObj = UnityEditor.Selection.activeObject as GameObject;
        PlayableDirector playableDirector = playableDirectorObj.GetComponent<PlayableDirector>();
        TimelineAsset timelineAsset = playableDirector.playableAsset as TimelineAsset;

        // 複製
        string path = AssetDatabase.GetAssetPath(timelineAsset);
        string newPath = path.Replace(".", "(Clone).");
        if (!AssetDatabase.CopyAsset(path, newPath))
        {
            Debug.LogError("Couldn't Clone Asset");
            return;
        }

        // バインディングのコピー
        TimelineAsset newTimelineAsset = AssetDatabase.LoadMainAssetAtPath(newPath) as TimelineAsset;
        PlayableBinding[] oldBindings = timelineAsset.outputs.ToArray();
        PlayableBinding[] newBindings = newTimelineAsset.outputs.ToArray();
        for (int i = 0; i < oldBindings.Length; i++)
        {
            playableDirector.playableAsset = timelineAsset;
            Object boundTo = playableDirector.GetGenericBinding(oldBindings[i].sourceObject);

            playableDirector.playableAsset = newTimelineAsset;
            playableDirector.SetGenericBinding(newBindings[i].sourceObject, boundTo);
        }

        // 公開された参照をコピーする
        playableDirector.playableAsset = newTimelineAsset;
        foreach (TrackAsset newTrackAsset in newTimelineAsset.GetRootTracks())
        {
            foreach (TimelineClip newClip in newTrackAsset.GetClips())
            {
                foreach (FieldInfo fieldInfo in newClip.asset.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                {
                    if (fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(ExposedReference<>))
                    {
                        // 古い公開名を取得する
                        object exposedReference = fieldInfo.GetValue(newClip.asset);
                        PropertyName oldExposedName = (PropertyName)fieldInfo.FieldType
                            .GetField("exposedName")
                            .GetValue(exposedReference);
                        bool isValid;

                        // 古い公開値を取得する
                        Object oldExposedValue = playableDirector.GetReferenceValue(oldExposedName, out isValid);
                        if (!isValid)
                        {
                            Debug.LogError("Failed to copy exposed references to duplicate timeline. Could not find: " + oldExposedName);
                            return;
                        }

                        // 構造体のexposedNameを置き換えます
                        PropertyName newExposedName = new PropertyName(UnityEditor.GUID.Generate().ToString());
                        fieldInfo.FieldType
                            .GetField("exposedName")
                            .SetValue(exposedReference, newExposedName);

                        // ExposedReferenceを設定します
                        fieldInfo.SetValue(newClip.asset, exposedReference);

                        // PlayableDirectorのリファレンスを設定する
                        playableDirector.SetReferenceValue(newExposedName, oldExposedValue);
                    }
                }
            }
        }
    }
}
最後に

もし、こんな事しなくても出来るとか、オペレーションで回避出来ると言う話であれば、どなたか教えて下さい。

要望とか多いので、ツールやら、Unityのエディタ拡張が最近多いな。。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?