この記事はUnity #3 Advent Calendar 2020の12/12(土)の記事です。
はじめに
この記事ではUnityのTimeline機能に存在するTimelineAction
とそれに関連する機能について解説します。
ターゲット
Unityを使った開発を行っておりTimeline機能を拡張して実装を進めているエンジニアがメインターゲットです。
Unityの基礎的な内容やTimeline、Editor拡張などで頻出する単語・機能などに関しての詳細な説明は省略しますので予めご了承ください。
またここで解説する機能はUnity Timeline 1.4.0以降から使えるようになるものです。
詳しくはchangelogを参照してください。
得られるもの
UnityEditor.Timeline.Actions.TimelineAction
の基本的な使い方を知ることができます。
この機能は主にTimelineウィンドウ上のコンテキストメニューに独自の処理を追加することを可能とします。
1.4.0以前のバージョンではTimelineウィンドウに関わるクラス群がほとんどinternal
な宣言になっていたこともあり、独自の処理をTimelineウィンドウ内に追加することは現実的ではなく、オリジナルのEditorWindow
を定義して利用者にはTimelineウィンドウとその独自ウィンドウを一緒に開いてもらって編集をするようなワークフローを組んでいた方も多いと思います。
今回登場したこのTimelineAction
の機能によりコンテキストメニューを使えるようになったので、そのような独自ウィンドウをわざわざ作らなくても済むことが大幅に増えました。
本題
Timeline機能も昔と比べてサポートが充実してきました。
公式のTimelineActionに関するAPIドキュメントを見に行くとしっかりとサンプルコードが載っています。
今回はこのサンプルコードを軸に解説を進めます。
[MenuEntry("Custom Actions/Sample Timeline Action")]
public class SampleTimelineAction : TimelineAction
{
public override ActionValidity Validate(ActionContext context)
{
return ActionValidity.Valid;
}
public override bool Execute(ActionContext context)
{
Debug.Log("Test Action");
return true;
}
[TimelineShortcut("SampleTimelineAction", KeyCode.Q)]
public static void HandleShortCut(ShortcutArguments args)
{
Invoker.InvokeWithSelected<SampleTimelineAction>();
}
}
TimelineAction
TimelineAction
の機能を使うためには**TimelineAction
クラスを継承します。**
詳細は後述するそれぞれの項目で解説しますが、このクラスを継承しただけではTimelineウィンドウ上では動作せず、MenuEntryAttribute
やTimelineShortcutAttribute
と組み合わせて使用することでTimelineウィンドウ上で処理を実行できるようになります。
public override ActionValidity Validate(ActionContext context)
後述のExecute
メソッドを実行するかどうかを検証するメソッドです。
ActionValidity
戻り値のActionValidity
によって動作が変わります。
ActionValidityの種別 |
Execute メソッドが実行されるかどうか |
MenuEntryAttribute を使用している場合の挙動 |
---|---|---|
ActionValidity.Valid | 実行されます。 | コンテキストメニューに選択可能な状態で表示されます。 |
ActionValidity.NotApplicable | 実行されません。 | コンテキストメニューには表示されません。 |
ActionValidity.Inavlid | 実行されません。 | コンテキストメニューに選択不可能な状態で表示されます。 |
特殊なのがActionValidity.NotApplicable
で、これはメニューにも表示されなくなります。
使い分けの仕方としては、**条件によって使用可能な処理はActionValidity.Invalid
を、そもそもその編集状態では使用することができない処理はActionValidity.NotApplicable
**という風にするのが良いと思います。
これは、1つのUnityプロジェクトの中で性質の違う複数のTimelineを編集する必要があるような環境で使えそうです。
(ゲーム開発で例えると、ガチャ演出のTimeline編集専用のActionと奥義演出のTimeline編集専用のAction機能が同居しているなどのケース)
逆に言えば、そこまで規模の大きくない編集環境であれば、基本的にはActionValidity.Valid
とActionValidity.Invalid
の2つを使えばよいと思います。
ActionContext
このActionが動作する際のTimelineウィンドウ上の様々な情報がActionContext
として引数に入ってきます。
それぞれのプロパティ(フィールド)の詳細は以下の通りです。
プロパティ(フィールド)名 | 注意事項など |
---|---|
PlayableDirector director |
TimelineEditor.inspectedDirector と同様の内容が入ります。Projectウィンドウで直接TimelineAsset を選択した状態だとnull が入ります。
|
TimelineAsset timeline |
TimelineEditor.inspectedAsset と同様の内容が入ります。 |
double? invocationTime |
コンテキストメニュー経由で実行した場合、右クリックした場所から時間を算出して秒数が入ります。※1 ショートカット経由での実行の場合はnull が入ります。
|
IEnumerable<TrackAsset> tracks |
SelectionManager.SelectedTracks() と同様の内容が入ります。※2 |
IEnumerable<TimelineClip> clips |
SelectionManager.SelectedClips() と同様の内容が入ります。※2 |
IEnumerable<IMarker> markers |
SelectionManager.SelectedMarkers() と同様の内容が入ります。※2 |
※1 クリップが置かれる場所を右クリックした際はその位置の再生時間が入ってきましたが、左側にあるトラックリストの部分を右クリックしてコンテキストメニューから実行した際に入る時間がよく分からない値になっていました。調査中です。 | |
※2 SelectionManager はinternal class です。 |
public override bool Execute(ActionContext context)
実際に処理したい内容をここに記述します。
引数にはValidate
メソッドのときと同様にActionContext
が入ってきます。
戻り値には処理の成否を返却します。
実行されるActionのインスタンスはActionManager
という内部クラスでキャッシュされて使い回すため、フィールドに値を持ったりする場合は注意してください。
MenuEntryAttribute
TimelineAction
を継承したクラスにこのAttribute
をつけることで、Timelineウィンドウ上のコンテキストメニューに処理を追加することができます。
機能としてはTimelineウィンドウの中でしか動作しないという点以外はUnityEditor.MenuItem
とほぼ同様の内容です。
標準機能のプライオリティに関しては MenuPriority
クラスで確認することができます。
TimelineAction
の場合、マーカー、トラック、クリップ(クリップが置かれていない場所を含む)を右クリックした際のコンテキストメニューに表示されます。
※マーカーのみ、トラックのみ、クリップのみに対応したい場合はそれぞれMarkerAction
,TrackAction
,ClipAction
が存在します。
TimelineShortcutAttribute
Timelineウィンドウ上でショートカットキーを使えるようにします。
機能としてはUnity2019から追加されたShortcuts Managerと同様ですが、このAttributeを使うことで自動的にTimelineのカテゴリに振り分けてくれます。
コンテキストメニューで処理する内容はショートカットキーでも同様に使いたいケースが多いことから、このTimelineAction
のサンプルで紹介されていますが、このAttribute自体はTimelineAction
と関係なく単独で動作します。
ショートカットキー周りは時間があれば別途記事を作って紹介するかもしれません。。
Invoker
とてもシンプルな名前ですが、TimelineAction
を含む各種Action
クラスの処理を外から手軽に呼び出せるようにしたユーティリティクラスです。
TimelineAction
の場合、bool InvokeWithSelected<T>() where T : TimelineAction
メソッドを使用することで、任意の独自Actionを呼び出すこと(ValidateしてExecuteするまで)が可能です。
引数に渡すActionContext
の用意やUndo処理なども含めて内部でやってくれるので、よほど特殊な事情がなければこのInvoker
クラスを経由して各種Actionクラスを実行したほうがよいでしょう。
オマケ
APIドキュメントにサンプルコードが書かれているのはとても有り難いことですが、内容は最低限しかないためイマイチどのように使うのかピンとこない人もいると思います。
実は標準的な機能(コピー&ペーストや削除など)も、このActionを使って定義されています。
※場所は↓(@の後ろは自分の使っているTimelineのバージョン)
com.unity.timeline@1.4.0/Editor/Actions/TimelineActions.cs
internal
なクラスを多用しているのでそのまま参考にできるわけではありませんが、それらの実装を見ることでイメージがかなり掴めるようになると思いますので、そちらも合わせて見てから自分の実装を進めると良いと思います。
おわりに
今回はTimelineAction
について解説してみました。
これ以外にも機能を限定したMarkerAction
,TrackAction
,ClipAction
も存在しますが、基本的な仕様はTimelineAction
と同様なので、この記事だけでも使えると思います。
Timelineもようやくコンテキストメニューも使えるようになり、拡張の幅もかなり広がってきました。
みなさんが開発しているツールが少しでも便利になってもらえれば幸いです。