2020/11/09
【開発日記】CharacterControllerでの移動時に入力方向へキャラクターを振り向け続ける方法
time 2018/11/01
今回は開発中のゲームに関連するちょっとしたお話です。
下の画像のような2Dベースのアクションゲームを作っている時、CharacterControllerで移動させるとキャラクターの振り向きが中途半端な位置で止まってしまうことがあります。
2Dアクションで途中で止まると困るので、入力方向に完全に振り向くまで回転させ続ける方法を考えてみました。
そもそも「2DアクションでCharacterControllerを使うのがおかしい」とも考えられますが、プレイヤーキャラクターに物理演算は使わない上、坂道での挙動やスクリプトからの移動制御もやりやすいので、私的には割とありかなーと思います。
まず現在私が使用している、移動用スクリプトの回転制御を行うためのメソッドを紹介します。
CharacterControllerから現在のベクトルを取得し、その方向に徐々に振り向きますが、移動入力を行わないとベクトルも0になって回転が止まってしまいます。
/// <summary> /// キャラクターの回転を行う /// </summary> protected void DoRotate() { // 現在の移動ベクトルを取得 Vector3 moveVelocity = characterController.velocity; moveVelocity.y = 0; // 角度と回転方向を取得 float value = Mathf.Min(1, rotate_speed * Time.deltaTime / Vector3.Angle(transform.forward, moveVelocity)); Vector3 newForward = Vector3.Slerp(transform.forward, moveVelocity, value); if (newForward != Vector3.zero) { transform.rotation = Quaternion.LookRotation(newForward, transform.up); } }
これを入力方向に向けて振り向き続けるようにするため、先ほどのメソッドを次のように修正します。
/// <summary> /// 現在の回転方向のベクトル /// </summary> private Vector3 currentRotateForward = Vector3.zero; /// <summary> /// キャラクターの回転を行う /// </summary> protected void DoRotate() { // 現在の移動ベクトルを取得 Vector3 moveVelocity = characterController.velocity; moveVelocity.y = 0; // 移動ベクトルが零ベクトル以外の場合は回転用ベクトルに設定 if (moveVelocity != Vector3.zero) { currentRotateForward = moveVelocity; } // 角度と回転方向を取得 float value = Mathf.Min(1, rotate_speed * Time.deltaTime / Vector3.Angle(transform.forward, currentRotateForward)); Vector3 newForward = Vector3.Slerp(transform.forward, currentRotateForward, value); if (newForward != Vector3.zero) { transform.rotation = Quaternion.LookRotation(newForward, transform.up); } }
ポイントは「移動ベクトルをフィールド変数に保持する」「移動入力されている場合のみcurrentRotateForward
を更新する」の2つです。
入力方向へ振り向き続けるには「最後に移動入力を行った方向のベクトルを保持しておく」ことが必要です。そのためのフィールド変数を1つ追加し、移動入力がされていない場合は変数を更新せずに回転方向を決定するようにします。
実際に動かすと下のような感じ。
GIFアニメーションでは分かりにくいですが、逆方向に1回しか移動入力していません。
ゲーム的には「振り向き中に攻撃できないようにする」などの対応が必要ですが、基本的な動きはこれで問題なさそうですね。