アニメーションツリー

はじめに

AnimationPlayerと合わせて、Godotはあらゆるゲームエンジンの中でもトップクラスの柔軟性をもつアニメーション・システムをもっています。トランスフォーム、ベジェ曲線、関数呼び出し、オーディオや副アニメーションのトラックが用意されているのみならず、あらゆるノードやリソースのどんなプロパティでもアニメーションできることは、非常に独特です。

ただし、それらのアニメーションをブレンドするには、AnimationPlayerでは固定のクロスフェード遷移のみなので、比較的制限されています。

AnimationTreeは、高度な遷移をするためにGodot 3.1で導入されたノードです。これは古いAnimationTreePlayerを置き換えるもので、膨大な量の機能と柔軟性を加えています。

AnimationTreeの作成

始める前にまず明らかにすべきは、AnimationTreeノードは自身のアニメーションは含みません。代わりにそれは、別にあるAnimationPlayerノードが持つアニメーションを利用します。これにより、従来通りアニメーションを編集(あるいは他の3Dシーンからインポート)でき、さらに再生をコントロールしたいときにこのノードを追加するのです。

AnimationTreeの最も一般的な使い道は3Dシーンです。シーンを3D交換フォーマットからインポートすると、通常はアニメーションはそのまま同梱されています(複数のものや、大きなものがインポートの際に分割されていても)。インポートされたGodotシーンでは最終的に、アニメーションはすべて一つのAnimationPlayerノードに格納されます。

Godotでは、インポートされたシーンを (インスタンス化あるいは継承せずに) 直接使うことは珍しいので、インポートされたシーンのための新しいシーンにAnimationTreeを追加することにします。そのあとAnimationTreeノードにて、インポートされたシーンの中に作られたAnimationPlayerを割り当ててください。

参考例として、三人称視点シューターデモ(英語) もそうなっています。

../../_images/animtree1.png

プレイヤー用の新しいシーンはKinematicBodyをルートにして作られています。このシーンの中には、元の.dae(Collada)ファイルがインスタンス化され、AnimationTreeノードが作成されてあります。

ツリーの作成

AnimationTreeでは主に3種類のノードが使えます:

  1. アニメーション・ノード。リンクされたAnimationTreeのアニメーションを参照します。
  2. アニメーションルート・ノード。副ノードとのブレンドに使われます。
  3. アニメーションブレンド・ノード。AnimationNodeBlendTreeの中で使用され、複数のインプットポートを持ち、一つのグラフでブレンドします。

AnimationTreeのルートノードを設定するには、いくつかの型が用意されています:

../../_images/animtree2.png
  • AnimationNodeAnimation: リストから選択したアニメーションを再生します。これは一番シンプルなルートノードで、通常は直接のルートとしては使用されません。
  • AnimationNodeBlendTree: mix、blend2、blend3、one shotなどのような、多くのブレンド型のノードを含んでいます。これはルートとしてよく使われるものの一つです。
  • AnimationNodeStateMachine: 一つのグラフに、複数のルートノードを子に持ちます。それぞれのノードはステートとして扱われ、ステートを切り替えるための機能をいくつも備えています。
  • AnimationNodeBlendSpace2D: ルートノードを2Dブレンドスペースに置けるようになります。二次元空間でブレンド位置をコントロールし、複数のアニメーションのミックスします。
  • AnimationNodeBlendSpace1D: 上記の簡略版です (一次元)。

ブレンド・ツリー

AnimationNodeBlendTreeはブレンド用で、ルートまたは通常のノードを含むことができます。ノードはメニューからグラフに追加します。

../../_images/animtree3.png

すべてのブレンドツリーには、標準でOutputノードが入っていて、アニメーションを再生するにはそこに何かをつなげる必要があります。

この機能を確認する一番簡単な方法は、Animationノードを直接つなげることです:

../../_images/animtree4.png

これは単純にアニメーションを再生します。実行する前にまずAnimationTreeがアクティブであることを確認してください。

下記は利用可能なノードの短い説明です:

Blend2 / Blend3

これらのノードは、2つあるいは3つのインプットをユーザー指定の値でブレンドします:

../../_images/animtree5.gif

より複雑なブレンドには、代わりにブレンドスペースを使うことをおすすめします。

ブレンドにはフィルターを使うこともでき、どのトラックをブレンド関数に渡すかどうかをコントロールできます。これはアニメーションをレイヤーに分けて重ね合わせるのに有用です。

../../_images/animtree6.png

OneShot

このノードは、副アニメーションを実行し、完了すると元に戻ります。フィルターだけでなく、フェードインとフェードアウトのブレンド時間もカスタマイズできます。

../../_images/animtree6b.gif

Seek

このノードは、グラフのどんな副子ノードに対してもシーク命令を送ります。時間をセットした後は、値は -1 に戻ります。

TimeScale

アニメーションの再生速度の変更 (あるいは逆再生) を可能にします。0 にセットするとアニメーションを一時停止します。

トランジション

とても単純なステートマシンです (StateMachineノードを扱いたくない時に)。複数のアニメーションを接続でき、トランジションの時間を指定できます。

BlendSpace2D

BlendSpace2D is a node to do advanced blending in two dimensions. Points are added to a two-dimensional space and then a position can be controlled to determine blending:

../../_images/animtree7.gif

X および Y の範囲でコントロールできます (それぞれ別の名称に変更可)。デフォルトでは、点はどこにでも置けます(座標系の上で右クリックするか、点を作成ボタンを使う)。三角形はドロネー分割で自動生成されます。

../../_images/animtree8.gif

三角形の自動作成をオフにすれば、三角形を手動で作成することもできますが、必要になることはあまり無いでしょう:

../../_images/animtree9.png

最後に、ブレンドモードは変更することができます。標準状態では、一番近い三角形の中で補完された点によってブレンドされますが、もし対象が(フレームごとに動かす)2Dアニメーションなら、離散モードに切り替えてもよいでしょう。あるいは、離散アニメーション間においても現在の再生位置を維持したい場合のために、キャリーモードもあります。モードはブレンドメニューから変更できます。

../../_images/animtree10.png

BlendSpace1D

これは2Dブレンドスペースと同様ですが、一次元のみです (そのため三角形は不要)。

StateMachine

このノードは比較的シンプルなステートマシンです。ルートノードを作り、線をつないで接続します。ステートは、独自のプロパティを持つトランジションを用いて接続します。トランジションは一方通行ですが、ふたつを互いに接続させあうことができます。

../../_images/animtree11.gif

トランジションにはいくつもの種類があります:

../../_images/animtree12.png
  • 即座 (Immediate): 次のステートへと即座に切り替わります。現在のステートが終わると、新しいほうの先頭から始まります。
  • 同期 (Sync): 次のステートへと即座に切り替わりますが、新しいステートでも古いステートと同じ再生位置になります。
  • 終わりに (At End): 現在のステートの再生位置が最後になるまで待ち、それから次のステートの先頭に切り替わります。

トランジションはまた、いくつかのプロパティを持ちます。トランジションをクリックすると、インスペクタ ドックに表示されます:

../../_images/animtree13.png
  • Switch Mode はトランジションの種類です (上記参照)。作成した後でもここで変更できます。
  • Auto Advance (自動移行)は、このステートに到達したらすぐにトランジションがオンになります。これは At End スイッチモードと合わせるのが最適です。
  • Advance Condition (移行条件) は、この条件が満たされた場合に自動移行させます。テキストフィールドには変数名を入れます。この変数はコードから変更することができます (詳しくは後述)。
  • Xfade Time は、このステートと次との間でのクロスフェードにかかる時間です。
  • Priority (優先度) は、コード内でのtravel()関数と共に使用します (詳しくは後述)。ひとつのステートから別へと移動するときの、このノードの優先度を設定します。
  • Disabled (無効) は、このトランジションを無効にします (ただし travel や自動移行では無視されます)。

ルート モーション

3Dアニメーションの作業では、スケルトンを動かすためにルート・スケルトン ボーンを用意するのが一般的なテクニックです。これにより、キャラクターを床に合わせて歩かせることが可能になります。また、ムービー場面においても、正確に物体に触れさせられるようになります。

Godot内でアニメーションを再生するときは、このボーンを ルート・モーション トラック に指定することができます。そうすると、そのボーンの見た目の変化は打ち消されます (アニメーションはそのまま)。

../../_images/animtree14.png

そのあと、実際のモーションはAnimationTree APIからトランスフォームとして取得します:

anim_tree.get_root_motion_transform()
animTree.GetRootMotionTransform();

これをKinematicBody.move_and_slideなどの関数に渡すことで、キャラクターの動きをコントロールできます。

また、ツールノードとしてRootMotionViewがあり、シーン中に置くことでキャラクターとアニメーション用のフロアが表示されます (通常このノードはゲーム中は無効にされます)。

../../_images/animtree15.gif

コードからコントロールする

ツリーを作成してプレビューしたら、最後に残る質問は「これを全部コードからコントロールする方法は?」です。

注意していただきたいのは、アニメーション ノードはリソースであり、したがって、すべてのインスタンス間で共有されます。ノードの値を直接変更すると、このAnimationTreeを使用するシーンにある、すべてのインスタンスも影響を受けます。しかし、これにはクールな応用方法もあります。例えば、アニメーションツリーの一部をコピー&ペーストできますし、(ステートマシンやブレンドスペースのような)複雑なレイアウトのノードを、異なるアニメーションツリー間で再利用できます。

実際のアニメーション データはAnimationTreeノードに格納されており、プロパティを通じてアクセスします。AnimationTreeの Parameters セクションに、リアルタイムで変更できるパラメーターが全てあるので確認してみてください:

../../_images/animtree16.png

This is handy because it makes it possible to animate them from an AnimationPlayer, or even the AnimationTree itself, allowing the realization of very complex animation logic.

これらの値をコードから変更する場合は、プロパティ パスを知る必要があります。それには、パラメーターの上にマウスをホバーするだけです。

../../_images/animtree17.png

そうすれば、それらを設定したり読み込めます:

anim_tree.set("parameters/eye_blend/blend_amount", 1.0)
# Simpler alternative form:
anim_tree["parameters/eye_blend/blend_amount"] = 1.0
animTree.Set("parameters/eye_blend/blend_amount", 1.0);

ステートマシン travel

GodotのStateMachine実装にあるナイスな機能のひとつは、travel (移動)です。現在のステートからの移動を指示すると、グラフは中間のものを全て通ってから、別のステートへと移ります。これはA* アルゴリズムにて行われます。

travel機能を使うには、まずAnimationTreeノードからAnimationNodeStateMachinePlayback オブジェクトを取得します (プロパティのひとつ)。

var state_machine = anim_tree["parameters/playback"]
AnimationNodeStateMachinePlayback stateMachine = (AnimationNodeStateMachinePlayback)animTree.Get("parameters/playback");

取得したら、その多くの関数の中からひとつ呼び出せば使えます:

state_machine.travel("SomeState")
stateMachine.Travel("SomeState")