UnityのRigidbodyコンポーネントを使ったキャラクター移動の実装
これは『オープンワールドRPGをUnityで作りたい』シリーズの記事です。
導入
今回はRigidbodyを使ってキャラ移動を実装しました。キャラクターの移動はプレイヤーの入力を受け取り、それをキャラクターに反映させることで実現されます。プレイヤーの入力を受けとる方法としてInput ManagerとInput Sytemを使ったものがありました。Input Sytemの方が新しいシステムのようなので、Input Systemを使ってプレイヤーの入力を受け取ることにしました。Input Systemについては以下の記事を参照してください。今回の実装ではInput Systemを使うので先に下記の記事を読むことをお勧めします。
キャラクター移動方法はCharacter Controllerコンポーネントを使用したもの、Rigidbodyを使用したものがあるようでした。両方法の違いは以下の動画がわかりやすかったです。
How to Move Characters In Unity 3D | Character Controllers Explained - YouTube
一度Character Controllerを使って実装してみましたが、設置判定がうまくいかなかったのでやめました。
環境
- Windows11
- Unity2022.3.16f1
- Input System 1.7.0
移動
実装
Input Actionの設定
PlayerゲームオブジェクトにPlayer Inputコンポーネントを追加し、Create Actionsボタンを押してInput Action Assetを作成します。今回は"PlayerInputActions"という名前にしました。デフォルトでMoveやLookといったActionがあります。追加でJumpというActionを追加します。ボタンの割り当てはお好きなようにしてください。特定のボタンに対する処理ではなく、Actionという抽象的なものを介してスクリプトを組めるのがInput Systemの強みです。
Input Action Assetを作成したらGenerate C# Classボタンを押してC#クラスを作成します。このクラスを介して入力を読み取ります。
プレイヤーの入力を受け付けて反映させる
基本的にはRigidbodyコンポーネントのAddForce(ベクトル、ForceMode.Impalseでゲームオブジェクトに力を加えることで移動させました。人間が走るのと同じように力を加えようとしました。地面をけって自分自身を運動させるイメージです。次のC#クラスを作成してください。
using UnityEngine; [RequireComponent(typeof(Rigidbody))] class PlayerMove : MonoBehaviour { [SerializeField] private float moveSpeed = 1.0f; [SerializeField] private bool isGrounded = false; [SerializeField] private float baseJumpPower = 3.0f; private PlayerInputActions playerInput; private Rigidbody rb; private void Awake() { playerInput = new PlayerInputActions(); playerInput.Enable(); rb = GetComponent<Rigidbody>(); } private void Update() { if (playerInput.Player.Move.IsPressed() && isGrounded) { var moveInput = playerInput.Player.Move.ReadValue<Vector2>(); var direction = new Vector3(moveInput.x, 1f, moveInput.y); // y軸方向にも少し力を加える。 rb.AddForce(direction, ForceMode.Impulse); } if (playerInput.Player.Jump.IsPressed() && isGrounded) { Jump(CalJumpPower()); } } private void OnCollisionStay(Collision collision) { isGrounded = true; } private void OnCollisionExit(Collision collision) { isGrounded = false; } private void Jump(Vector3 jumpPower) { rb.AddForce(jumpPower, ForceMode.Impulse); } private Vector3 CalJumpPower() { var moveInput = playerInput.Player.Move.ReadValue<Vector2>(); var jumpPower = new Vector3(moveInput.x, baseJumpPower, moveInput.y); return jumpPower; } }
こいつをそのまま追加するだけだと、入力に応じてオブジェクトが簡単に吹っ飛んでいきます。それを防ぐためにRigidbodyコンポーネントのMassを60に設定します。また、Dragを1に設定します(これは無くてもいいかも)。
結果
動作結果はこちら。
課題
- 坂を上るときに最も早く移動できる特殊能力もち。
- 坂のColliderにタグを付けて、それに応じてスピードを変える処理を追加する。
- 別の実装を考える。
- そういう仕様にしてしまう。
- 壁に接触しているとジャンプ力が上がる。
- 接地判定の処理を変える。
- 良い感じのアニメーションを追加して違和感をなくす。
キャラクターの向きを変える
この時点ではキャラクターの向き自体は制御されていません。この章では移動する方向に身体の正面を向けるようにします。
実装
結果
課題
カメラの向きを考慮して移動させる
実装
結果
課題
アニメーションを付ける
これまではプリミティブな形のオブジェクトを対象に操作してきました。ここからは、実際にキャラクターのモデルを入れてアニメーションを付け加えていきます。