UNITY Editor拡張で、タイムラインをスクリプトから生成する
お題
タイムラインを自動生成しよう
トラックやクリップも外から作成してみます
それに伴い、エディタ拡張の勉強
メニューよりEditorWindowを表示
とりあえず最も汎用的な?メニュの拡張から
メニューの拡張
Editor拡張で最も使われると思うので、よーく覚えよう
UnityEditor.MenuItem - Unity スクリプトリファレンス
MenuItemを使う
ドキュメントの通り、非常に機能が豊富なので細かい事は説明しません
まず、Editor専用コードなので、Editorディレクトリを作りその下にコードを置く事
そして、Editor拡張は静的関数しか呼べないので、そういう設計にする事
主な機能をざっと
メニューアイテムの追加
[MenuItem("hoge/fuga")]
のように属性をつけると、メニューに hoge->fuga と追加される
メニュー名に日本語も使えます
当然そのメニューを選んだ時に、その関数が呼ばれます
ホットキーも簡単に付ける事ができます
また、Validateもする事が出来ますし、メニューの表示順番も変更できます
Validate関数を設定すれば、関数がFalseを返すと無効、Trueを返すと有効になります
ヒエラルキー
MenuItemのパスの頭をGameObjectにすると、ヒエラルキーで右クリックした際のメニューに追加できます
[MenuItem("GameObject/CustomEditor")] private static void Create() { Debug.Log("Menu"); }
ヒエラルキー右クリックでちゃんと表示されました
もちろん、メニューの のGameObjectにも表示される
Assets
MenuItemのパスの先頭をAssetsにすると、Assetsビューのコンテキストメニューに表示される
[MenuItem("Assets/CustomEditor", false, 1)] private static void Create() { Debug.Log("Menu"); }
もちろん、メニューのAssetsにも表示される
CONTEXT
コンポーネントの 右上の3点アイコンを押したときのメニューを作れます!
もちろん、自作コンポーネントだけじゃなく、UNITYのデフォルトコンポーネントも可能です
[MenuItem("CONTEXT/PlayableDirector/CustomEditor", false, 1)] private static void Create() { Debug.Log("Menu"); }
今回はPlayableDirectorコンポーネントにメニューを追加しました
今回使うもの
今回は、選択したGameObjectにPlayableDirectorコンポーネントを追加したいので
ヒエラルキー上のGameObjectのコンテキストメニューに追加する
コンテキストメニュー
public class CustomEditorWindow : EditorWindow { [MenuItem("GameObject/CustomEditor", false, 1)] private static void Create() { // 生成 GetWindow<CustomEditorWindow>("CustomEditor"); }
ヒエラルキーのGameObjectメニューにCustomEditorを追加します
そして、CustomEditorWindow(自分のクラス)を呼び、GUIを表示させます
今回は EditorWindowを継承し、ウインドウを表示させます
EditorWindow
private void OnGUI() { using (new GUILayout.HorizontalScope()) { targetGo_ = Selection.activeGameObject; if (GUILayout.Button("CreateTimeline")) { // ここにボタン押したときの処理が入る } } }
とりあえずボタンが1個あるだけの単純なウインドウ
以上でEditor拡張のおさらい終了
Timeline等をコードから生成
本題という事になる
GameObjectにPlayableDirectorのアタッチ
if(targetGo is null) { return; } // 選択中のGameObjectにPlayableDirectorコンポーネントをつける var director = targetGo.GetComponent<PlayableDirector>(); if(director == null) { director = targetGo.AddComponent<PlayableDirector>(); }
AddComponentを使って普通にPlayableDirectorを作成する
TimelineAssetを作成しAssetデータベースへ保存する
TimelineAssetを作成します
つまり、タイムラインの情報すべてを保存するものです
ScriptableObjectで作成します
ただし、このままでは、シーン上に作られます
実際の運用では、タイムラインはファイル(Asset)にして読み込んで使うと思うので
AssetDatabaseに登録します
拡張子は playableです
// TimelineAssetの作成 var timelineAsset = playableDirector.playableAsset as TimelineAsset; if (timelineAsset == null) { timelineAsset = ScriptableObject.CreateInstance<TimelineAsset>(); director .playableAsset = timelineAsset; } var path = "Assets/Resources/sample.playable"; AssetDatabase.DeleteAsset(path); AssetDatabase.CreateAsset(timelineAsset, path); AssetDatabase.SaveAssets();
AssetDatabaseの仕様で、ディレクトリが無い場合はエラーになるので、ディレクトリは事前に作っておく事
そして、既にAssetが存在する場合は上書きするとエラーになるので、事前にDeleteしておきます
SaveAssetは、即座にデータベースに反映するおまじないです
トラックの作成&バインディングを設定
今回はGroupトラックを作成し、そこにトラックを作成します
型は前回作った NewPlayableTrackです
Bindingにはゲームオブジェクトをつけます。今回はCubeという名前のゲームオブジェクトをつけます
var groupTrack = timelineAsset.CreateTrack<GroupTrack>(null, "Group"); var track = timelineAsset.CreateTrack<NewPlayableTrack>(groupTrack, "NewPlayable"); var b = GameObject.Find("Cube"); director.SetGenericBinding(track, b);
クリップ作成とKeyFrame作成
クリップを作成します。もちろん NewPlayableAssetで
そしてそのクリップにKeyFrame(AnimationCurve)を設定します
今回は最初が1fで、デフォルトのカーブでエンドが0fになる形で
もちろん、カーブのEaseを変えたり、KeyFrameを増やす事は容易
var clip = track.CreateClip<NewPlayableAsset>(); clip.CreateCurves(null); var curve = new AnimationCurve(); curve.AddKey(new Keyframe(0f, 1f)); curve.AddKey(new Keyframe((float)clip.duration, 0f)); clip.curves.SetCurve("", typeof(NewPlayableAsset), "hoge", curve);
リフレッシュ
最後にリフレッシュ
EditorUtility.SetDirty(timelineAsset); TimelineEditor.Refresh(RefreshReason.ContentsAddedOrRemoved);
成果物
とりあえず、目的の事は出来た