はるきちの雑記

対戦よろしくおねがいします

【Unity】一人称視点カメラの上下方向の回転を制御したい

現在一人称視点のゲームを作ってるんですが、カメラの操作を実装しているときに少し悩んだところがあったので、忘れないように記事を残しときます。

まずカメラをマウスの移動に合わせて回転させる処理ですが、

        // マウスの移動方向に回転量を掛けた値を代入する
        xRotate = Input.GetAxis("Mouse X") * cameraRotateSpeed;
        yRotate = Input.GetAxis("Mouse Y") * cameraRotateSpeed;

        // カメラをマウスの移動量に応じて回転させる
        camera.transform.RotateAround(player.transform.position, Vector3.up, xRotate);
        camera.transform.RotateAround(player.transform.position, transform.right, -yRotate);

これでマウスの移動に合わせてカメラが回転します。

xRotateはマウスの横方向の移動量を取得、
yRotateはマウスの縦方向の移動量を取得しています。
cameraRotateSpeedはゲーム上で言うところの感度です。

変数を見れば想像つくと思いますが、xRotateはカメラの横方向でyRotateはカメラの縦方向の回転させるために使います。
RotateAround関数は、第1引数に回転に用いる中心、第2引数に回転軸、第3引数に回転する方向を指定します。


ここで、カメラの回転する処理部分で記述されているVector3.upは、ワールド座標のy軸(0, 1, 0)を軸として使っています。
ワールド座標とは、3D空間全体の中心を中心座標として座標を表します。
なので、オブジェクトの向きなどは考慮されずに向きを変えることができるので、オブジェクトがどんなに傾いていようが常に同じ方向へ回転させることができます。


transform.rightは、オブジェクト自身の座標のx軸(1, 0, 0)を軸として使っています。
オブジェクトの座標をとっているので、オブジェクトの向きが変わると、回転する方向も変化します。

これでカメラの回転制御は7割くらいは完成してるのですが、ここである処理を加えます。
それがカメラの上下の回転制御です。

現状、今のだとカメラが上下方向に対して360°回ってしまいます。
普通の人間ならこんな首の動かし方したら終わるので、上下方向に対する回転制御を実装します。

コードはこんな感じ

        // マウスの移動方向に回転量を掛けた値を代入する
        xRotate = Input.GetAxis("Mouse X") * cameraRotateSpeed;
        yRotate = Input.GetAxis("Mouse Y") * cameraRotateSpeed;

        // カメラの上下の回転量(x軸の回転量)を取得
        yRotateParam = transform.localEulerAngles.x;

        // カメラのインスペクターの回転量と同期させる
        // カメラのx軸の回転量が180を超えていた場合
        if (yRotateParam > 180)
        {
            // 0~180、0~-180で回転量を表現できるよう計算を行う
            yRotateParam = yRotateParam - 360;
        }

        // カメラの上方向の回転量が指定の下限より大きい場合
        // カメラの回転方向が0より大きい場合
        if (yRotateParam >= rotateLimitMin && yRotate > 0)
        {
            // カメラをマウスの移動量に応じて回転させる
            camera.transform.RotateAround(player.transform.position, transform.right, -yRotate);
        }

        // カメラの下方向の回転量が指定の上限より小さい場合
        // カメラの回転方向が0より小さい場合
        if (yRotateParam <= rotateLimitMax && yRotate < 0)
        {
            // カメラをマウスの移動量に応じて回転させる
            camera.transform.RotateAround(player.transform.position, transform.right, -yRotate);
        }

        // カメラをマウスの移動量に応じて回転させる
        camera.transform.RotateAround(player.transform.position, Vector3.up, xRotate);


少しだけif文とかを付け足しました。
コメントでほとんど説明してますが、追加したところを上から順に説明しようと思います。

        // カメラの上下の回転量(x軸の回転量)を取得
        yRotateParam = transform.localEulerAngles.x;

これはインスペクターのx軸の回転量を取得しています。
上下方向の回転制御をするために用います。

        // カメラのインスペクターの回転量と同期させる
        // カメラのx軸の回転量が180を超えていた場合
        if (yRotateParam > 180)
        {
            // 0~180、0~-180で回転量を表現できるよう計算を行う
            yRotateParam = yRotateParam - 360;
        }

これはlocalEulerAnglesだと回転量を0から360で表現するのに対し、
インスペクター上では0から180、181以上は-180から0で表現しているので、
180を超えた回転量は-180から0の表記に収めてインスペクター上の表現と同じにするようにしています。

        // カメラの上方向の回転量が指定の下限より大きい場合
        // カメラの回転方向が0より大きい場合
        if (yRotateParam >= rotateLimitMin && yRotate > 0)
        {
            // カメラをマウスの移動量に応じて回転させる
            camera.transform.RotateAround(player.transform.position, transform.right, -yRotate);
        }

カメラの上方向に対する回転制御です。
インスペクターの回転量が制限値より大きく、マウスが上方向に移動している場合、{}内の処理を実行します。
カメラを上方向にx軸を回転させると、xの回転量がマイナスになったので制限値の変数名もMinがついてます。

        // カメラの下方向の回転量が指定の上限より小さい場合
        // カメラの回転方向が0より小さい場合
        if (yRotateParam <= rotateLimitMax && yRotate < 0)
        {
            // カメラをマウスの移動量に応じて回転させる
            camera.transform.RotateAround(player.transform.position, transform.right, -yRotate);
        }

カメラの下方向に対する回転制御です。
インスペクターの回転量が制限値より小さく、マウスが下方向に移動している場合、{}内の処理を実行します。
カメラを下方向にx軸を回転させると、xの回転量がプラスになったので制限値の変数名もMaxがついてます。


上記の追記したスクリプトをカメラにアタッチすると、こんな感じの動作になると思います。

カメラが上下方向に対して一定の角度まで傾いていることが確認できると思います。
多分この先、壁があった時すり抜けないようにとかいろいろ考えなきゃいけないものがありそうだけど、いったんこれで完成とします。