もりもりゲーム制作ブログ

それほどもりもりしてません。Unityの忘備録的ブログ。

【Unity3D】回転の制限とカメラついて

FPSやTPSのゲームではカメラの回転に制限がかかっています。

ですがカメラをtransdorm.Rotate()でただ回転させるだけだと、上下への回転(x軸に対する回転)が一回転しておかしなことになってしまいます。
今回はこれを解決する
「回転に制限のついたカメラ」を作ります。
手っ取り早く動かしたい人は完成スクリプトコピペしてください

前提

やりたいこと自体はこのイメージです。

f:id:monimoni114514:20190131004332p:plain
実装イメージ

仕様的な内容

マウスの移動に合わせ、上下に制限つき、左右に制限なしで回転するカメラ
を作ります。以下要素

  • 入力はマウスの移動から取る
  • X軸をもとに回転する上下に回転の制限をつける
  • Y軸をもとに回転する⇒回転制限なし
  • 回転の制限となる値はエディターから設定する
用意するもの
  • カメラオブジェクト
  • CameraController.csスクリプト
  • 地面や配置物⇒カメラがどのように回転しているか把握するため

X軸とY軸それぞれを回転させる

とりあえず回転させます。

    void Update()
    {
        var _inputX = Input.GetAxis("Mouse X");
        var _inputY = Input.GetAxis("Mouse Y");
        transform.Rotate(_inputY, _inputX, 0);
    }

マウスのXの移動量を_inputXに、Yの移動量を_inputYに代入し
transform.Rotateで回転させていますが、
このままだとY軸の回転が常にワールド基準のY軸を元にした回転ではなくなるため、
X軸の回転とY軸の回転の基準をそれぞれ分ける必要があります。

    void Update()
    {
        var _inputX = Input.GetAxis("Mouse X");
        var _inputY = Input.GetAxis("Mouse Y");

        //X軸回転
        var localAngle = transform.localEulerAngles;
        localAngle.x += _inputY;
        transform.localEulerAngles = localAngle;
        //Y軸回転
        var angle = transform.eulerAngles;
        angle.y += _inputX;
        transform.eulerAngles = angle;
    }

transform.Rotateではなく、transformの回転をx,y,zの値で表すlocalEulerAnglesとeulerAnglesの値を取得し、
そのx,yの値を変更してから代入しなおすことで回転させています。
localEulerAnglesはオブジェクト自体がもつ基準による回転情報で、
eulerAnglesはワールド基準による回転情報です。

回転に制限をつける

エディター上の回転の値を、transform.rotation.xのように取得することはできません。
transform.rotationはQuaternion(四元数)で表現されています。
今回は四元数ではなくx,y,zの値で表現されたEulerAnglesなどがあるのでこれを角度制限のフックに使います。

    void Update()
    {
        var _inputX = Input.GetAxis("Mouse X");
        var _inputY = Input.GetAxis("Mouse Y");
        float maxLimit = 60, minLimit = 360 - maxLimit;

        //X軸回転
        var localAngle = transform.localEulerAngles;
        localAngle.x += _inputY;
        if (localAngle.x > maxLimit && localAngle.x < 180)
            localAngle.x = maxLimit;
        if (localAngle.x < minLimit && localAngle.x > 180)
            localAngle.x = minLimit;
        transform.localEulerAngles = localAngle;


        //Y軸回転
        var angle = transform.eulerAngles;
        angle.y += _inputX;
        transform.eulerAngles = angle;
    }

eulerAnglesとlocalEulerAnglesのx,y,zは時計回りに0°~360°の値になっているので180°前後の条件も付けています。

完成スクリプト

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    [SerializeField]
    float viewAngle;//エディター上で60を入力
    float _inputX, _inputY;
    
    void Update()
    {
        _inputX = Input.GetAxis("Mouse X");
        _inputY = Input.GetAxis("Mouse Y");

        Rotate(_inputX, _inputY, viewAngle);
    }

    void Rotate(float _inputX,float _inputY,float limit)
    {
        float maxLimit = limit, minLimit = 360 - maxLimit;
        //X軸回転
        var localAngle = transform.localEulerAngles;
        localAngle.x += _inputY;
        if (localAngle.x > maxLimit && localAngle.x < 180)
            localAngle.x = maxLimit;
        if (localAngle.x < minLimit && localAngle.x > 180)
            localAngle.x = minLimit;
        transform.localEulerAngles = localAngle;
        //Y軸回転
        var angle = transform.eulerAngles;
        angle.y += _inputX;
        transform.eulerAngles = angle;
    }
}