以前のチュートリアルはこちらです:
細かい移動の演出
以前のチュートリアルでアイドリング状態から走りアニメーションを切り替えるシステムを作りました。しかし、走り出した時や止まった時は動きが不自然でした。ここでは、ブレンドツリーという機能を使って移動する動きをより細かく設定します。具体的に移動速度によって以下のパターンに切り替えます:
- アイドリング(静止)
- 歩き
- 小走り
- 走り
追加のアニメーションが必要ですので、Mixamoから適切な「歩き」と「小走り」アニメーションを探します。ダウンロード手順は前回のチュートリアル同様ですので、説明を省きます。
インポートしたアニメーションは前回同様に、リグ設定を変えてループ再生を有効にします。
ブレンドツリー
静止、歩き、小走りと走りの切り替えは前回のような遷移ではなく、よりパワフルなブレンドツリーを使います。ブレンドツリーは文字通りと複数のアニメーションをブレンドさせる方法です。つまり、歩き→小走りという明確なトランジションではなく、移動速度に合わせて演出を徐々に歩きから小走りにブレンドしていきます。
まず、アニメーターの「OnGround」サブステートマシンに「Locomotion」(移動)という新しいブレンドツリーを追加します。
インスペクターで「Blend Tree」と書かれているところをダブルクリックして、ブレンドツリーを編集します。
ブレンドツリーは1次元(1D)と2次元(2D)のツリーがあります。一次元のツリーは一つのパラメータだけで制御します。とりあえずこちらを使ってみます。ブレンドを制御するパラメータをMovementSpeedにします。そして、ブレンドするアニメーションクリップを追加します。
ブレンドをプレビューしたいので、インスペクターの下で再生を開始します。
プレビューしてみると、歩きと小走り、小走りと走りがブレンドされている状態だとキャラクターの走り方がおかしいのが分かると思います。
原因はダウンロードした小走りのアニメーションです。他のアニメーションは1サイクル(左右一歩ずつ)しかありませんが、小走りは何歩かがあります。Mixamoからダウンロードしなおさなくても直せます。プロジェクトウィンドウで街頭のクリップを選択して、インスペクターで編集します。
「Animation」タブで終了のフレームを調整します。
変更を適用して、ブレンドツリーの編集に戻ります。アイドリングから走りまでのブレンドが滑らかになったことが確認できます。
デフォルトで制御するパラメータの最高値が「1」になっていますが、MovementSpeedはキャラクターの最高速度まで上がります。
歩く速度と小走りの速度もThresholdパラメータで設定します。
細かい微調整が残っていますが、プレーして動作確認をしながら行いましょう。
ブレンドツリーの調整が一旦終わったので、アニメーターで繋げます。最初は、「Locomotion」をレイヤーのデフォルトアニメーションにします。
せっかく作りましたが、既存の「Idle」と「Run」を削除します。「Locomotion」がすべてその役割を果たしてくれるからです。
「Locomotion」から「(Up) Base Layer」への遷移を追加します。
動作確認します。
ここまで出来たら各モーションの再生速度やThresholdでさらに自然な動きを目指します。例えば、上の動画でアイドリングから歩きへの切り替えがまだイマイチですから、歩きの位置を調整しました。
2次元のブレンドツリー
移動をさらにリアルにしたいなら、曲がった時に曲がりながら走るアニメーションをブレンドツリーに追加しましょう。
これが使える前にアニメーターに新しいパラメーターを追加します。
このパラメーターをスクリプトで設定するので、Characterスクリプトにプライベートプロパティを追加します。
bool isOnGround = false; // 地面に立っているかどうか
bool isJumping = false; // ジャンプしているかどうか
Vector3 groundVelocity = Vector3.zero; // 移動速度
float turnAngle = 0f; // 曲がる角度
ApplyMotionでアバターの向きを変えるコードに曲がりの角度計算を追加します。
// プレーヤーの向きを変える
if (avatar != null)
{
Vector3 rotateTarget = new Vector3(movement.x, 0, movement.z);
if (rotateTarget.magnitude > 0.1f)
{
Quaternion lookRotation = Quaternion.LookRotation(rotateTarget);
avatar.transform.rotation = Quaternion.Lerp(lookRotation, avatar.transform.rotation, turnSmoothing);
// 向かっている方向と向かおうとしている方向の角度を求める
// 度で返される値をラジアンに変換する
turnAngle = (Mathf.PI / 180f)Quaternion.Angle(lookRotation, avatar.transform.rotation);
// 左右の曲がりを識別したいので、左ならマイナス値にする
if (movementInput.x < 0)
{
turnAngle *= -1f;
}
}
}
そして、Updateでこの結果をAnimatorに送ります。
void Update()
{
if (animator != null)
{
animator.SetBool("OnGround", isOnGround);
animator.SetFloat("MovementSpeed", groundVelocity.magnitude);
animator.SetFloat("Turn", turnAngle);
}
}
一応、Animatorウィンドウを見ながら動作確認をしましょう。左右曲がる時に、Turnパラメーターが変わります。
ここまで出来たら、ブレンドツリーを選択して、タイプを1Dから「2D Freeform Cartesian」に変えます。
パラメータをMovementSpeedとTurnにします。
ブレンドするモーションがすべて同じ位置に配置されてしまうので、切り離します。
x軸がMovementSpeedですので、以前の1Dのブレンドツリーを再現します。
ここでもう一度動作確認をします。以前と同じ動きになっていることを確認します。
追加した曲がりながら走るモーションを2度追加します。
2つ目のアニメーションのミラー(左右反転)パラメータにチェックを入れます。これで右に曲がるモーションと左に曲がるモーションになります。
2つのモーションを走りと揃えて配置します。
動作確認してみると、曲がった時に確かに曲がるアニメーションが再生されますが、左右に移動方向を変えた時にアニメーションが急に切り替わってしまうのが気になります。滑らかにするためにコードを少し修正します。
Quaternion lookRotation = Quaternion.LookRotation(rotateTarget);
avatar.transform.rotation = Quaternion.Lerp(lookRotation, avatar.transform.rotation, turnSmoothing);
// 向かっている方向と向かおうとしている方向の角度を求める。
// 度で返される値をラジアンに変換する
float newAngle = (Mathf.PI / 180f) * Quaternion.Angle(lookRotation, avatar.transform.rotation);
// 左右の曲がりを識別したいので、左ならマイナス値にする
if (movementInput.x < 0)
{
newAngle *= -1f;
}
turnAngle = Mathf.Lerp(turnAngle, newAngle, 0.1f); // Lerp(補完)で変化を滑らかにする
この修正で動作確認をしてみると…
曲がりアニメーションがちゃんと切り替わります。
Leave a Reply