今回はアニメーターコントローラのBlendTreeを使ってキャラクターに細かい動作をさせてみようと思います。

でラジコン操作で動かすキャラクターを曲がる時に体を傾けたアニメーションにさせる事は出来ていました。
こちらの記事を見る前にそちらを見て頂くとBlend Treeとはなんぞや!?
という事がわかると思いますので、参考にしてください。
今回の機能を作成すると、
↑のような感じで元の向きからどれだけ反対方向に向いたかでアニメーションを変化させる事が出来ます。
今回は、ラジコン操作(↑のキーを押したらキャラクターが向いている方向に進む)ではなく、押した方向キーの方へ移動し、元々向いていた方向からの角度でアニメーションを変更していこうと思います。
正直なところ、向いている方向からどの程度右や左に向いたのか?を計算する方法がわからず四苦八苦していました。
Standard Assetsに入っている3rdPersonControllerのスクリプトのように作りたいのですが、いかんせん見ても理解出来なかったので、参考にしつつ自分流に作ってみました。
今見ている方向からどの程度向きを変えたかを計算
アニメーターコントローラのBlend Treeを作成する前に、今見ている方向から押したキーの方向に何度変わったか?
を計算するスクリプトを作成します。
面倒くさい処理をした移動スクリプト
まずは最初に面倒くさい回転値の計算を使ったキャラクターの移動スクリプトを作成してみます。
こちらは結構苦労して作ったし、何かの役に立つかもしれないので残してありますが、この後もっと簡単に回転値を計算するスクリプトを作成したので、そちらを参考にしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | using UnityEngine; using System.Collections; public class DetailBlendTree : MonoBehaviour { private Animator animator; private CharacterController cCon; private float x; private float y; private Vector3 velocity; void Start () { animator = GetComponent<Animator>(); cCon = GetComponent<CharacterController>(); } void Update () { if(cCon.isGrounded) { velocity = Vector3.zero; x = Input.GetAxis("Horizontal"); y = Input.GetAxis("Vertical"); var input = new Vector3(x, 0f, y); // 方向キーが多少押されている if(input.magnitude > 0f) { animator.SetFloat("Speed", input.magnitude); // これで角度の変化率の取得が可能 animator.SetFloat("Turn", Mathf.Repeat(Mathf.Repeat(Mathf.Atan2(x, y) * Mathf.Rad2Deg, 360.0f) - transform.eulerAngles.y, 360.0f)); transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, Mathf.Repeat(Mathf.Atan2(x, y) * Mathf.Rad2Deg, 360.0f), transform.eulerAngles.z), 180.0f * Time.deltaTime); velocity += input.normalized * 2; // キーの押しが小さすぎる場合は移動しない } else { animator.SetFloat("Speed", 0f); } } velocity.y += Physics.gravity.y * Time.deltaTime; cCon.Move(velocity * Time.deltaTime); } } |
inputは押したキーの移動値を設定したベクトルです。
移動値が0よりあれば移動させます。
アニメーターコントローラのSpeed値にはinput.magnitudeの値を設定します。
input.magnitudeでベクトルの長さを取得出来ます。
次に向いている方角から何度角度が変わったかを計算する処理です。
1 2 3 | Mathf.Repeat(Mathf.Repeat(Mathf.Atan2(x, y) * Mathf.Rad2Deg, 360.0f) - transform.eulerAngles.y, 360.0f) |
これはいったい何をやっているんだ!?
というのがほとんどの人の意見であると思います。
うまい方法がわからなかったので、ずいぶんわかりづらいスクリプトになっていると思います。
まずは押した方向の角度を計算します。
Mathf.Atan2(x, y)でラジアン値、それにMathf.Rad2Degをかける事で角度を算出出来ます。
3rdPersonで使っていたので、使ってみました。詳しい所はわかりません。
方向キーを押した角度から現在の角度を引いた値をTurnに入れます。
向いている方向が奥側(奥側を0度)だった時に左を90度向いたら270度、右を90度向いたら90度がTurnに設定されます。
0~180度までが右まわり、180~360度までが左回りをしたことになります。
詳しく突っ込まれても説明出来ないのでご容赦ください・・・(-.-)
方向キーの向いている角度をMathf.Repeatで360度以内に設定します。これはマイナスの角度が設定された時に0~360の間に調整する為の処理です。
現在の角度transform.eulerAngles.yを引いた後にもこの処理をしています。
アニメーターコントローラのパラメータを設定したら、自分自身の角度を押した方向キーの方に向けていきます。
1 2 3 4 5 | transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, Mathf.Repeat(Mathf.Atan2(x, y) * Mathf.Rad2Deg, 360.0f), transform.eulerAngles.z), 180.0f * Time.deltaTime); |
Quaternion.RotateTowardsで第1引数から第2引数への角度へ徐々に変化させます。
変化の度合いは1秒間で180度変わる速度で変化させます。180の部分を大きくすると早く変化します。
回転値の計算をわかりやすく改造したキャラクター移動スクリプト
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | using UnityEngine; using System.Collections; public class DetailBlendTree : MonoBehaviour { private Animator animator; private CharacterController characterController; private Vector3 velocity; [SerializeField] private float walkSpeed = 1.25f; [SerializeField] private float rotateSpeed = 180f; void Start () { animator = GetComponent<Animator>(); characterController = GetComponent<CharacterController>(); } void Update () { if(characterController.isGrounded) { velocity = Vector3.zero; var input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); // 方向キーが多少押されている if(input.magnitude > 0f) { animator.SetFloat("Speed", input.magnitude); animator.SetFloat("Turn", Quaternion.FromToRotation(transform.forward, input).eulerAngles.y); // これで角度の変化率の表示 Debug.Log(Quaternion.FromToRotation(transform.forward, input).eulerAngles.y); transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, Quaternion.LookRotation(input).eulerAngles.y, transform.eulerAngles.z), rotateSpeed * Time.deltaTime); velocity += input.normalized * walkSpeed; // キーの押しが小さすぎる場合は移動しない } else { animator.SetFloat("Speed", 0f); } } velocity.y += Physics.gravity.y * Time.deltaTime; characterController.Move(velocity * Time.deltaTime); } } |
Debug.Logは角度がどうなっているか確認する為に記載しています。
回転を計算していた
1 2 3 | Mathf.Repeat(Mathf.Repeat(Mathf.Atan2(x, y) * Mathf.Rad2Deg, 360.0f) - transform.eulerAngles.y, 360.0f) |
の部分を
1 2 3 | Quaternion.FromToRotation(transform.forward, input).eulerAngles.y |
に変更しました。
Quaternion.FromToRotationを使うと第1引数の方向と第2引数の方向の角度が計算出来ます。
Quaternion.FromToRotationに関しては

も参考にしてください。
また、キャラクターの角度を計算している部分では
1 2 3 | transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, Mathf.Repeat(Mathf.Atan2(x, y) * Mathf.Rad2Deg, 360.0f), transform.eulerAngles.z), 180.0f * Time.deltaTime) |
の部分を
1 2 3 | transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, Quaternion.LookRotation(input).eulerAngles.y, transform.eulerAngles.z), rotateSpeed * Time.deltaTime); |
と変更しています。
キャラクターを最終的に向かせる角度はQuaternion.LookRotationでinputの方向の角度を取得し設定するようにします。
これで多少回転方法が簡単になったとは思いますが、回転の理解が苦手な人(そうですわたしが・・・・謎)にはあまり変わらないかもしれませんね・・・・(^_^;)
アニメーターコントローラのSpeed、Turnの値を渡す事が出来たので、その値によってアニメーションを変化させましょう。
アニメーターコントローラでブレンドツリーを作成
アニメーターコントローラを作っていきます。
上のようにCreate StateからFrom New Blend Treeを選択してブレンドツリーを作成します。
名前をWalkRunに変更しておきます。
CreateからEmptyを選択し、名前をIdleに変更して初期状態を作成しておきます。
IdleにはHumanoidIdleクリップを設定しておきます。
Idle→WalkRun、WalkRun→IdleへとMake Transitionし、それぞれの条件をSpeedが0.1以上、Speedが0.1以下とします。
両方ともHasExitTimeのチェックは外しておきます。
Idle→WalkRunは上のようになります。
次はWalkRunをダブルクリックし、ブレンドツリーの中身を作成していきます。
WalkRunをダブルクリックした後、ブレンドツリー内のBlend Treeを右クリックし、Add Blend Treeを選択し、2つBlend Treeを作成します。
出来たBlend Treeはそれぞれインスペクタ上でWalkとRunという名前に変更してください。
Blend TreeはBlend Typeを1D、ParameterをSpeedにしAutomate Thresholdsのチェックを外し、
WalkのThresholdは0.1、RunのThresholdは0.8を設定します。
このしきい値がブレンドの度合いを表します。Speedがより0.1に近い場合はWalkのアニメーションが濃くなります。
逆に0.8に近い場合はRunのアニメーションが濃くなります。
しきい値より下または上になると完全にそちらのアニメーションになります。
WalkとRunのブレンドツリーをそれぞれ選択し、Blend Typeを1D、ParameterをTurnにします。
ここまで作成すると上のようになります。
元のBlend TreeではアニメーションパラメータのSpeed値によってWalk、Runのブレンドをし、その後Walk、Run内でさらにTurnの値によってアニメーションをブレンドする事になります。
角度の変更度合いでアニメーションを変える
ではWalkから作成していきます。
インスペクタの+をクリックしAdd Motion Fieldを選択します。
まずはしきい値(Threshold)を上の画像のように設定します。
向いている方向が0度だった時方向キーを押した位置によって返ってくる角度は上の画像のようになります。
つまり右回りに回転する場合、45度の時は緩やかに、90度を超えたら急速に回転するアニメーションを再生します。
アニメーションは3rdPersonControllerで使用されているHumanoid系を設定します。
向いている方向からの角度によってアニメーションを設定してください。
上の画像が設定したアニメーションクリップです。
Runのブレンドツリーもやる事は同じです。
上のようにアニメーションクリップを変更しただけで、Walkと同じです。
これでアニメーターコントローラの設定が終わったので、
Unityの実行ボタンを押して確認してみます。
ちょっとわかりづらいですね・・・。
input.magnitudeをSpeedの値として設定しているので、歩くモーションはほぼブレンドされません。
例えばShiftキーを押している時は歩くアニメーションにする。
といったフラグを用意すると歩くアニメーションも使え、無駄に歩行時のアニメーションを作るということにはならないかと思います。