Blenderでモーションをたくさん作ったので、今回はまず停止・歩き・走りのモーションをキャラクターに設定していこうと思います。
ループするモーションの制作については前の記事にまとめたので、今回はUnityでAnimatorを使って設定する方法をやっていきます。
もくじ
アニメーションの仕様
今回は、停止・歩き・走りの3種類をキャラクターのスピードに応じて自動で切り替わるように設定します。
ゲームは物理演算で移動するように作っており、カプセル型のRigidbodyのキャラの中にアニメーションする3Dモデルを入れます。
キャラのY軸での回転はスクリプトから行うようになっているので、前方へ移動する仕草だけを切り替える形です。
FBXの読み込みと設定
まずプロジェクトにFBXをインポートしたら、リグをHumanoidに設定してApplyします。

Animationのタブを開くとFBXの中のアニメーションクリップが下の方に並んでいるので、1つずつ設定していきます。

今回のようにその場でループする仕草をするモーションの場合、僕の設定は大体こんな感じです。

1つずつ見ていきます。
Loop Time
モーションをループさせるか最後のフレームで停止させるかです。
今回は全部ループするアニメーションなのでチェックします。
Bake Into Pose
ポーズの変化を座標の移動として扱うかどうかです。
これをチェックしないとアニメーションによる移動が発生してしまうので、今回は必ず全部チェックします。
忘れるとモデルが物理演算オブジェクトの中でローカル座標でどこかに行ってしまいます。
Based Upon
モーションの位置や回転の補正をするかどうかです。
Blenderで元々ループするように作っていて全体の動きに何も問題ない場合、Originalにするのがオススメです。
OriginalはBlenderでの座標や回転の値をそのまま使用します。
それ以外の値の設定はだいたいこんな感じのようです。基本的にはモーションが完成している時点で補正不要なことが多いと思いますが、必要な際は適宜修正します。
Root Transform Rotation | Body Orientation | 最初のフレームでのHipの回転が正面を向くように補正 |
Root Transform Position(Y) | Feet | 最初のフレームでの低い方の足の高さを地面の高さに合わせるように補正 |
Root Transform Position(Y) | Center Of Mass | 最初のフレームでのモーションの中心が地面の高さになるよう補正 |
Root Trandform Position(XZ) | Center Of Mass | 最初のフレームでのモーションの中心が(0, 0)になるよう補正 |
ただし、Root Transform Position(Y)はなぜかBlenderでモーションを地面にぴったり作っていてもキャラが浮き上がったり地面にめり込んだりすることがあります…。
適用先のモデルのサイズ(モーション用モデルとの身長の差や倍率?)によるものなのか理由はよく分からないのですが、Originalに設定したうえでOffsetの値を入れて調整すると良いかと思います。
Mirror
モーションを反転するかどうかです。
この項目は、アニメーションクリップから設定する必要はあまりないのかなと思います…。右利きと左利きのキャラを作りたい場合など、ここから設定すると全てが反転してしまうのでモーションをコピーする必要性が出てきます。
反転についてはステートの方で設定できるので、右利き用Animator Controllerと左利き用Animator Controllerを分けておくか1つのAnimator Controllerの中でBoolで条件分岐させるのが良いのかなと思います。
Animator Controllerを作る
Projectタブで+からAnimator Controllerを作って開きます。
最初から3つのステートがありますが、とりあえず空いたところを右クリックして「Create State」から「From New Blend Tree」を選びます。

名前はとりあえずMoveにしました。適宜好きな名前で大丈夫です。

次にMoveを開いて、インスペクタータブから設定をします。

Blend Type
1Dにします。これはParameterに設定した1つのFloatの値が変わることによって複数のアニメーションクリップを切り替えるタイプのブレンドです。
Parameters

まず、スクリプトからFloatの値を受け取る必要があるので、Animatorタブ左側の+からFloatで「Speed」のパラメーターを作ります。
今回はキャラのスピードで切り替えようと思うので、パラメーターの名前はSpeedにしました。
これをBlend TreeのParameterに設定します。
Motion
右下の+を押して欄を3つ作り、モーションを設定します。
Thresholdの欄がありますが、初期状態ではAutomate Thresholdがオンになっていて自動的に値が設定されるようになっています(個数で割り算して3つの場合は0.0f・0.5f・1.0f)。
とりあえずはこのままで実際に動かしてみて、動きが合わなければAutomate Thresholdのチェックを外して自分で値を設定するのが良いかと思います。
スクリプトでの処理
あとは0.0f〜1.0fのスピードをスクリプトでアニメーションに送ればOKです。
現在のプレイヤーキャラのスピードですが、2通り考えられるかと思います。
1つはコントローラーから受け取った入力方向のベクトルの長さです。これは元々コントローラーから0.0f~1.0fの長さで来ているものなので、アニメーション用の値としては扱いやすいです。
ただし、キャラを壁際に押し込んだ時に走る動作をします。
もう1つはRigidbodyのVelocityの長さです。これは動いているオブジェクトの実際のスピードなので、最大値が1.0fになるようにするのはひと手間かかりそうです。(デバッグでVelocityの最大値を計測しておいて割り出すとか…)
こちらはキャラを壁際に押し込んでも立ち止まることになります。
どちらが良いかは好みですが、このスピードのベクトルの長さがFloatで必要です。
ベクトルの長さのFloatはVector3.Magnitude(ベクトル)で算出できます。
これをAnimatorのSetFloatでパラメーターの名前と一緒に毎フレーム渡せばOKです。
Animator animator;
void FixedUpdate()
{
float currentSpeed = Vector3.Magnitude(towardDir);
animator.SetFloat("Speed", currentSpeed);
}
ただし、プレイヤーの入力はスティックを離して突然0になることがあります。
キャラ移動のVelocityも(慣性をどのように処理するかによりますが)急速に0になることがあります。
この値をそのまま使うと唐突にアニメーションが切り替わってギクシャクした動きになってしまうので、Mathf.Lerp()を使って少し補正をかけると良い感じになります。
Animator animator;
float moveSpeed;
void FixedUpdate()
{
float currentSpeed = Vector3.Magnitude(towardDir);
moveSpeed = Mathf.Lerp(moveSpeed, currentSpeed, 0.2f);
animator.SetFloat("Speed", moveSpeed);
}
以上でOKです!
動かしてみるとこんな感じです。
アニメーションの管理について
僕はBlenderでモーションを作成しており、1つのFBXファイルにある程度まとまった数のアクション(アニメーションクリップ)を入れてUnityにインポートしています。
自作している都合上、モデルやスクリプトで実際に動かしてみてから調整することがよくあります。
ここでの問題が、インポートし直すとUnityで行った設定が消えてしまうことです。画像ファイルとかだと差し替えても設定は消えないと思いますが、FBXは消えてしまうようです(少なくとも僕の環境では…)。
Blender側で全てのアクションをバラバラに管理するのは大変ですし、1つの修正だけで全部の設定をやり直すのも大変です。
実は、Unityの方でFBXからアニメーションクリップを抜き出して単体で保存することができます。
やり方は、ProjectタブでFBXファイルを開いて中にあるアニメーションクリップを選択してCtrl+Dです。
Humanoidの設定をした後でコピーします(Bake Into PoseやBased Uponの設定項目がついた状態でコピーされます)。

このコピー方法は以前に一時期できなくなっていたことがあり、Unityの公式のドキュメントでもアニメーションクリップはFBXに紐づいたものとして扱っているようなので、オススメかどうかはよく分かりません。
ただしFBXから切り離すことで利便性が上がる場面もあると思うので、必要に応じて試してみるのも良いかなと思います。
おわりに
今回はアニメーションの1Dを使ったやり方だったのですが、他の方法もいろいろあります。
2Dを使ったスニーク歩きの実装はこちら↓