TimelineAssetをEditor用Scriptから生成するメモ



Editor用ScriptからTimelineAssetを作ったときの要点メモです
Unity2017.1.0f3
(ver上がるとAPIはいろいろ変わったり増えたりしそう)

#要点
TrackAssetはTimelineAsset.CreateTrackで生成
PlayableAssetやRecordableなAnimationClipはAssetDatabase.AddObjectToAssetを使ってTimelineAssetの子にする
https://docs.unity3d.com/ScriptReference/AssetDatabase.AddObjectToAsset.html
(通常UI操作で追加されるPlayableAssetはasset.hideFlags = HideFlags.HideInHierarchy;してある)


##Timelineの構成

![TimelineAsset.png](https://qiita-image-store.s3.amazonaws.com/0/86424/e6cf097f-5a04-5391-4161-130a3d90b07d.png)
参考: http://www.shibuya24.info/entry/timeline_basis

###TimlineAsset
TrackAssetを束ねる長
あとは全体の再生時間設定ぐらいしか持ってない
https://docs.unity3d.com/2017.1/Documentation/ScriptReference/Timeline.TimelineAsset.html

###TrackAsset
シーン上のObjectとバインドする
TimelineClipを束ねて保持している
継承していろいろ種類がある
https://docs.unity3d.com/2017.1/Documentation/ScriptReference/Timeline.TrackAsset.html

###TimelineClip + PlayableAsset
TimelineClipは、いつからいつまで　どうブレンドするか　という情報だけを持っている
https://docs.unity3d.com/2017.1/Documentation/ScriptReference/Timeline.TimelineClip.html

PlayableAssetはTimelineClipが具体的に何をするかの情報を持っている
例えばAnimationPlayableAssetなら"どのアニメーションをどの位置で行うか"
https://docs.unity3d.com/2017.1/Documentation/ScriptReference/Timeline.AnimationPlayableAsset.html

#サンプル

##備考
作ったあとはAssetDatabase.SaveAssets()やAssetDatabase.Refresh()をしないとUnityが検知できないかも

##TimelineAssetを生成して保存する

```C#:
       public static TimelineAsset CreateTimelineAsset(string path) {
              var timelineAsset = ScriptableObject.CreateInstance<TimelineAsset>();
              AssetDatabase.CreateAsset(timelineAsset, path);
              return timelineAsset;
       }
```

##TrackAssetをTimelineAssetに追加する
何かのTrackの子にしたいならparentを指定する
GruopTrackなんかはこれで親子関係にする前提のTrack

```C#:
       public static T CreateTrackAsset<T>(TimelineAsset timelineAsset, string trackName, TrackAsset parent = null) where T : TrackAsset {
              return (T)timelineAsset.CreateTrack(typeof(T), parent, trackName);
       }
```

##PlayableAssetを生成し、TimelineAssetの子に追加する

```C#:
       public static T CreatePlayableAsset<T>(TimelineAsset timelineAsset, string playableAssetName) where T : PlayableAsset {
              var playableAsset = (T)ScriptableObject.CreateInstance(typeof(T));
              playableAsset.name = playableAssetName;
              playableAsset.hideFlags = HideFlags.HideInHierarchy;
              AssetDatabase.AddObjectToAsset(playableAsset, timelineAsset);
              return playableAsset;
       }
```

##TimelineClipを生成し、TrackAssetに追加する

```C#:
       public static TimelineClip CreateTimelineClip(TrackAsset parent, PlayableAsset playableAsset) {
              var timelineClip = parent.CreateDefaultClip();
              timelineClip.asset = playableAsset;
              return timelineClip;
       }
```

##AnimationTrackのRecordableなAnimationClipを追加する

![Recordable.png](https://qiita-image-store.s3.amazonaws.com/0/86424/11303c84-3c60-4156-4529-085c1476e60a.png)

編集できるAnimationClipとして追加する
たぶんもっとマシな方法もあるはず

```C#:
       public static void AddAnimationClip(AnimationTrack trackAsset, TimelineClip timelineClip, AnimationClip clip) {
              if (timelineClip.asset as AnimationPlayableAsset == null) {
                     Debug.LogError("null AnimationPlayableAsset");
                     return;
              }
              var setClipFieldInfo = typeof(TrackAsset).GetField("m_AnimClip", BindingFlags.NonPublic | BindingFlags.Instance);
              setClipFieldInfo.SetValue(trackAsset, clip);
              var setRecordableFieldInfo = typeof(TimelineClip).GetField("m_Recordable", BindingFlags.NonPublic | BindingFlags.Instance);
              setRecordableFieldInfo.SetValue(timelineClip, true);
              (timelineClip.asset as AnimationPlayableAsset).clip = clip;
              AssetDatabase.AddObjectToAsset(clip, trackAsset.timelineAsset);
       }
```

##作成テスト
```C#:
	[MenuItem("Test/TimelineCreateTest")]
	static void TimelineCreateTest() {
		var timelineAsset = CreateTimelineAsset("Assets/test.playable");
		var groupTrack = CreateTrackAsset<GroupTrack>(timelineAsset, "Parent");
		var animationTrack = CreateTrackAsset<AnimationTrack>(timelineAsset, "Child", groupTrack);
		var animationPlayableAsset = CreatePlayableAsset<AnimationPlayableAsset>(timelineAsset, "AnimationPlayableAsset");
		var timelineClip = CreateTimelineClip(animationTrack, animationPlayableAsset);

		AddRecordableAnimationClip(animationTrack, timelineClip, new AnimationClip { name = "TestRecordable" });
		AssetDatabase.SaveAssets();
	}
```