質問: ### Timelineを複製したとき参照が外れる問題を解決したい Unity(2018.3.6f1)で並列で5つくらいのTimelineを作って、タイミングごとに切り替えているのですが 複製Ctrl+dでDuplicateしたTimelineを見てみると参照が外れてしまいます。 1つや2つのTimelineならいいのですが20程度Timelineを量産するときにも、いちいち手作業で参照先を入れ直さないといけないのでしょうか? 初歩的な質問ですがお答えいただきますと幸いです。 複製前 ![イメージ説明](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/612ce61d9e3eb882b94cc3c0e16b4d12.png) 複製後(参照が外れている) ![イメージ説明](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/9b729e24e2ef2b2342f2f9205927af9a.png)
回答: おうかがいしますが、ご質問者さんのおっしゃる状況は... * プロジェクトビュー内にあるタイムラインアセット(四角が重なったようなアイコンのファイル)を複製する。 * 複製されたアセットファイルをシーン上のオブジェクトが持つPlayable Directorコンポーネントの「Playable」にセットして、そのオブジェクトを選択した状態でタイムラインエディタを表示してみる。 * すると、各トラックやトラック内にあるクリップの配置は複製元と同じになっているが、エディタウィンドウ左側にある各トラックとシーン上オブジェクトの関連付けは全部「None」に戻ってしまっている。 といったケースと、あるいは... * シーン上にあるPlayable Directorを持つオブジェクトを選択してタイムラインエディタを表示する。 * エディタ上には各種トラックが縦に並んでおり、それぞれのトラックにはクリップが配置されている。 * トラックをいくつか選択して複製すると、それら複製トラックがタイムラインエディタの下の方(グループトラック内の子トラックなら、そのグループ内の下の方)に追加される。 * このとき、各トラック内のクリップの配置や設定は複製元のトラックと同じだが、シーン上オブジェクトの関連付けは全部「None」に戻ってしまっている。 というケースのどちらに近い(あるいはいずれとも違う)でしょうか? 前者の場合、Duplicating a Timeline loses all the Bindings Unity v2017.2.0b6 - Unity Forumに寄せられたseant_unityさんの案が役立ちそうです。 通常、シーン上にあるPlayable Directorを持つオブジェクトを選択して複製した場合、複製後のオブジェクトを選択してタイムラインエディタを表示してみると複製前と同じトラック・クリップ配置で、かつトラックとオブジェクトの参照もちゃんと繋がっているでしょうが、そもそもこれだとタイムラインアセットは複製元と同じものを共有している状態のはずです。ですので複製物と複製元を個別に編集するわけにはいかないかと思います。 seant_unityさんのスクリプトをEditorフォルダに入れ、メニューの「Timeline」→「Duplicate With Bindings」で複製した場合は、オブジェクトの複製に併せてタイムラインアセットの複製も行い、その後トラックとオブジェクトの関連付けを行っているようです。タイムラインアセットファイルが独立するので、複製物と複製元の個別編集ができるようになるという理屈のようでした。 後者の場合はどうするかですが、ちょっと検索してみたところではこれだという案は見つけられませんでした。 トラックの複製 - Unity マニュアルによると... > > トラックを複製すると、クリップ、ブレンド、インスペクターのプロパティーをコピーします。複製したトラックがゲームオブジェクトにバインドされている場合、そのバインドは None (無し) にリセットされます。 > > > などと記載されており、バインディングが外れてしまうのは正常な動作のようですね。 仕方ないので、下記のようなスクリプトを作成してみました。 ``` using System.Linq; using System.Reflection; using UnityEditor; using UnityEditor.Timeline; using UnityEngine; using UnityEngine.Playables; using UnityEngine.Timeline; public static class TrackDuplicator { [MenuItem("Utility/Timeline/Duplicate Track With Bindings", true)] public static bool DuplicateTrackValidate() { // 編集中のタイムラインと関連しているPlayableDirectorが存在し、 // かつ一つ以上のトラックを選択している場合にメニューを使用可能にする return (TimelineEditor.inspectedDirector != null) && Selection.objects.OfType().Any(); } [MenuItem("Utility/Timeline/Duplicate Track With Bindings")] public static void DuplicateTrack() { // トラック複製メソッドを探す // クラスやメソッドが見つからなければ処理を中止 var trackExtensionsType = typeof(TimelineEditor).Assembly.GetType("UnityEditor.Timeline.TrackExtensions"); if (trackExtensionsType == null) { Debug.LogError("TrackExtensions not found."); return; } // internal static TrackAsset Duplicate(this TrackAsset track, PlayableDirector director, TimelineAsset destinationTimeline = null) var duplicateInfo = trackExtensionsType.GetMethod( "Duplicate", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Static); if (duplicateInfo == null) { Debug.LogError("TrackExtensions.Duplicate not found."); return; } // バインディングするために現在編集中のPlayableDirectorが必要 var director = TimelineEditor.inspectedDirector; // 複製メソッドに渡す引数の配列をあらかじめ作っておき // 複製の際にはそれぞれの複製元を0番要素に代入して渡すことにする var duplicateArgs = new[] {(object)null, director, null}; // 選択されているトラックを列挙し... foreach (var source in Selection.objects.OfType()) { // 複製して... duplicateArgs[0] = source; var clone = duplicateInfo.Invoke(null, duplicateArgs) as TrackAsset; // 複製元から複製先にバインディング状態をコピーする CopyBindings(source, clone, director); } // どうやら最後にエディタをリフレッシュしてやらないと追加されたトラックが表示されない様子でした TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved); } private static void CopyBindings(TrackAsset fromTrack, TrackAsset toTrack, PlayableDirector director) { // 元のトラックが参照しているのと同じオブジェクトを、複製トラックに対してバインドする director.SetGenericBinding(toTrack, director.GetGenericBinding(fromTrack)); // もし子トラックを持っているなら... if (fromTrack.GetChildTracks().Any()) { // 子トラックも複製されているはずなので、それぞれ再帰的にバインドする var fromChildren = fromTrack.GetChildTracks().ToArray(); var toChildren = toTrack.GetChildTracks().ToArray(); for (var i = 0; i < fromChildren.Length; i++) { CopyBindings(fromChildren[i], toChildren[i], director); } } } } ``` これをEditorフォルダに入れた状態でタイムラインエディタを開き、複製したいトラックを選択してメニューの「Utility」→「Timeline」→「Duplicate Track With Bindings」を実行すると、トラックのバインディングが維持されたまま複製されるかと思います(ちなみに、メニュー階層は動作と関係ありませんので、ご自由にわかりやすい名前で整理してしまっても問題ありません)。 おそらくトラックの種類によらず(グループトラックであっても)複製できると思うのですが、おかしなところを見つけましたらコメントいただけると助かります。また、トラック複製に隠しメソッドを使っており、バージョンアップで動作しなくなる可能性もあります。すみません...