はるきちの雑記

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

【Unity】カメラワークについて考える

前回僕がアップしたうんちみたいなゲームを、無理言って周りの人にやらせました。
そしたら想像してたよりもちゃんとしたアドバイスなどをもらいました。本当に感謝してます。
正直ゲームの出来もあんまよくないから、結構ふざけた意見しかないかなと思ってました、ごめんなさい;;


アドバイスの中でも、特に多かったものとしては

「カメラワークがクソ」

が9割を占めてました。


何言ってんだ~~?って思いながら実際に自分がネットにあげた3D半裸男をやってみると、確かにおかしい…
下の動画が実際に操作している様子です。

なんかパントマイムやってるように見えるんですが、実際はカメラがつっかえるような感覚があり、動画ではどんなにマウスを動かしても一定以上カメラが動かないような現象が見られました。

原因を探ってみたら、以下の2つが主な理由でした。
 
 ・マウスカーソルの現在位置をもとにカメラの操作を行っていた
 ・マウスカーソルを画面外まで動かせるようにしていた

なので今回のことがまた起きないよう、カメラワークの制御に関するコードの修正箇所を簡単にまとめておこうかなと思います。
まず、マウスカーソルが画面外に出ないようにする処理ですが、

    void Start()
    {
        // マウスカーソルを動かせないようにする
        Cursor.lockState = CursorLockMode.Locked;
        // マウスカーソルを非表示にする
        Cursor.visible = false;
    }

このように実装してみました。
これでスタートボタンをクリックしたらマウスカーソルが非表示になり、画面外に移動してしまうことがなくなるはずです。
また、ポーズ画面関連でのマウスカーソルの処理としては、

        // 時間が止まっている場合
        if (Mathf.Approximately(Time.timeScale, 0f))
        {
            // マウスカーソルを動かせるようにする
            Cursor.lockState = CursorLockMode.None;
            // マウスカーソルを表示にする
            Cursor.visible = true;
        }
        // 時間が止まっていない場合
        else
        {
            // マウスカーソルを動かせないようにする
            Cursor.lockState = CursorLockMode.Locked;
            // マウスカーソルを非表示にする
            Cursor.visible = false;
        }

こんな感じに実装してみました。
コードの動きとしてはコメントに書いてある通りなのですが、ポーズ画面中はマウスカーソルを動かせるようにし、ポーズ画面を解除したときはマウスカーソルが動かせないようにしました。

ちなみに、Cursorでマウスカーソルの制御を色々と変更することができるそうです。
上記のを含めてCursorで実現可能な動作としては

        // マウスカーソル表示
        Cursor.visible = true;
        // マウスカーソル非表示
        Cursor.visible = false;

        // マウスカーソルを自由に動かせる
        Cursor.lockState = CursorLockMode.None;
        // マウスカーソルを画面内で動かせる
        Cursor.lockState = CursorLockMode.Confined;
        // マウスカーソルを画面中央にロックする
        Cursor.lockState = CursorLockMode.Locked;

とかがあるみたいです。結構使い道がありそう


さっき実装したコードをもとに実行してみたら、マウスが画面中央から移動しなくはなったんですが、今度はカメラがまっっったく動かないという現象が起きました。
これの原因としては、冒頭でも書いたようにマウスカーソルの現在位置をもとにカメラの回転量を決めていたからです。
コードでいうとこんなかんじ

        // マウスの現在位置の座標を、移動前のマウスの座標で引いた値を代入
        Vector3 nowMousePosition = Input.mousePosition - lastMousePosition;

        // 回転速度とマウスの位置座標の差分を掛けた値を代入
        newAngle = Vector3.zero;
        newAngle.x = xRotateParam * nowMousePosition.x;

        // カメラをプレイヤーの位置座標を中心にして回転させる
        cameraObject.transform.RotateAround(player.transform.position, Vector3.up, newAngle.x);

        // 現在のマウスの位置座標を、最後のマウスの位置座標として代入する
        lastMousePosition = Input.mousePosition;

以前のマウスカーソルと現在のマウスカーソルの位置の差分を取得して、それをカメラの回転量として使用しています。
ただ、マウスカーソルが動かなくなってしまった以上、こんなソースコードはクソの役にも立ちません。
なので、以下のように修正しました。

        // マウスのX方向の移動量と回転速度を掛けた値を代入
        float xRotate = xRotateParam * Input.GetAxis("Mouse X");

        // カメラをプレイヤーの位置座標を中心にして回転させる
        cameraObject.transform.RotateAround(player.transform.position, Vector3.up, xRotate);

ずいぶんスリムなコードになりました。
修正後のコードの動きとしては、マウスをどれだけ動かしたかで回転量が決まります。
なのでマウスカーソルの位置は見てないので、さっきまでの現象はもう発生しないはず。


実際に動かしてみました。

おお~~~いいかんじになりました。
それにEscキーを押すたびにカーソルが中心に固定されてますね。
なんとか実装したい処理が実現できたので、これでカメラワークの修正を終わりにしようと思います。