【Unity】アニメーション中、指定の位置に到達するように位置を補正する
ジャンプやダッシュジャンプを用いて障害物を登るというケースはよく有ります。この高さにアニメーションが一致すれば問題は無いのですが、任意の段差や距離をジャンプしたいといったケースは多々あります。
そういったケースの場合、幾つか解決の手法はありますが、今回はAnimator.MatchTargetを使用した解決法をメモします。
Animator.MatchTarget
Animator.MatchTargetは、アニメーションの指定タイミングでゲームオブジェクトの位置及び回転が到達するように調整するAPIです。
例えば下のように、ジャンプ開始モーションから補正を開始して着地時に指定位置に到達するような、微妙な位置を調整したり出来ます。
到達して欲しい位置は、単純なRoot位置だけではなくBodyやLeftHand、RightHand、LeftFoot、RightFootといった調整が出来ます。
例えば上のGifアニメでは、左足が着地する位置に合わせて位置を調整しています。
実際に使ってみる
StateMachineBehaviourの用意
実際に使ってみます。
まず、普通にジャンプするアニメーションを用意します。そのままだとジャンプ力が足りず、変な所に着地してしまいます。
このアニメーションに補正をかける訳ですが、実行時にステートマシンを調べるのも面倒なので、StateMachineBehaviourを使います。Mecanimでステートを選択中にAdd Behaviourで挙動を追加。
追加するコードはこんな感じです。
座標とウェイトの調整
コンポーネントは下のようになります。
まずTarget Body Partは「MatchPositionが到達して欲しいパーツ」です。先程も書いた通り「ルート、体、右手、右足、左手、左足」が指定出来ます。
逆にMatchPositionは、指定パーツが到達する位置(絶対値)で、Match Rotationが回転です。
この動きを、Weightsで制御します。Position Wieghtは、X/Y/Z方向にそれぞれ対応したウェイトです。例えばYを0に設定しておくと、MatchPositionでY軸にズレていてもY方向に動きません。
今回は単なる移動なので、とりあえずMatch PositionとPosition Weightを調整します。
Target Body PartをLeft footに変更し、Match Positionを想定の位置に調整。
アニメーションのタイミング調整
このStateMachineBehaviourのStartとEndが重要なポイントです。
MatchTargetは、Startから開始してEndのタイミングで対象の位置に到達します。そのため、キャラクターが動き始めたタイミングをStart、停止するタイミングをEndに指定します。
見るべきは、時間ではなくパーセントの方です。例えば下のアニメーションの場合、だいたい50.6%~76%くらいの位置で移動していますので、startは0.506、endは0.76と設定しておきます。この辺りは要微調整です。
これで、タイミングや位置の調整が上手くいっているならば、着地のタイミングで対象位置に到達するような感じでアニメーションしてくれます。
注意点
ApplyRootMotoinで動いている
MatchTargetですが、ApplyRootMotoinで動作しています。つまり、ApplyRootMotoinにチェックが入っていないと動作しません。
が、逆を言えばApply Root Motoinにチェックが入っていればRootMotionの無いアニメーションでも動作します。
例えばユニティちゃんのアニメーションにはRootMotoinが入っていませんが、着地のタイミングに合わせて目標地点に到達するように調整出来ます。
もしApplyRootMotoinを付けたくない場合は、下の記事が参考になりそうです。
移動速度は距離を時間で割った速度で、等速
MatchTargetですが、基本的に移動速度は一定速度(距離を時間で割った速度)です。そのため、距離があまりにも想定アニメーションと比較して離れすぎている場合、非常に気持ちの悪い感じの動きになります。
また、基本的に目標地点へ一直線で動くので、カーブを描いて到達して欲しいようなケースでは有効ではないです。
なので、補正程度に使用するのが良さそうです。
MatchTarget補正中にステートの補完が走ると変な位置に到達する
MatchTargetで移動中、アニメーションのステートがブレンドを開始すると、妙な位置に到達する事があります。
機能するMatchTargetは一つのみ
機能するMatchTargetは一つのみです。重複する場合、上に配置したStateMachieneBehaviourが優先されます。また、同様にサブステートがある場合は親に設定したStateMachieneBehaviourが優先されます。
なお、下のStartが上より早い場合、無視されるっぽいです。
画面外に跳ねて、地面に着地する的な。