UnityのRigidbodyコンポーネントを使ったキャラクター移動の実装

これは『オープンワールドRPGをUnityで作りたい』シリーズの記事です。

rumakuga.hatenablog.com

導入

今回はRigidbodyを使ってキャラ移動を実装しました。キャラクターの移動はプレイヤーの入力を受け取り、それをキャラクターに反映させることで実現されます。プレイヤーの入力を受けとる方法としてInput ManagerとInput Sytemを使ったものがありました。Input Sytemの方が新しいシステムのようなので、Input Systemを使ってプレイヤーの入力を受け取ることにしました。Input Systemについては以下の記事を参照してください。今回の実装ではInput Systemを使うので先に下記の記事を読むことをお勧めします。

forpro.unity3d.jp

キャラクター移動方法は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の強みです。

Jump Actionを追加。この画像ではゲームパッドで遊ぶことを想定している。

Input Action Assetを作成したらGenerate C# Classボタンを押してC#クラスを作成します。このクラスを介して入力を読み取ります。

作成したInput Action Assetをクリックし、InspectorからGenetate C# Classボタンを押してC#クラスを作成。
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に設定します(これは無くてもいいかも)。

Mass=65, Drag=1, Freez RotationのXとYにチェック
動かす対象のキャラクターのRigidbodyコンポーネントの設定

結果

動作結果はこちら。

youtu.be

課題

  • 坂を上るときに最も早く移動できる特殊能力もち。
    • 坂のColliderにタグを付けて、それに応じてスピードを変える処理を追加する。
    • 別の実装を考える。
    • そういう仕様にしてしまう。
  • 壁に接触しているとジャンプ力が上がる。
    • 接地判定の処理を変える。
    • 良い感じのアニメーションを追加して違和感をなくす。

キャラクターの向きを変える

この時点ではキャラクターの向き自体は制御されていません。この章では移動する方向に身体の正面を向けるようにします。

実装

結果

課題

カメラの向きを考慮して移動させる

実装

結果

課題

アニメーションを付ける

これまではプリミティブな形のオブジェクトを対象に操作してきました。ここからは、実際にキャラクターのモデルを入れてアニメーションを付け加えていきます。

実装

結果

課題