三人称の旋回カメラ
Assets/
Scenes/
Arena.unity
Scripts/
すでにあるものこのレッスンで追加このレッスンで置き換え
二段目です。FollowCamera は決まった角度から見ているだけなので、Knight の後ろ側を一度も確認できません。Main Camera から外して、代わりにこちらを付けてください。
三人称カメラは「棒の先に付いたカメラ」だと思うのが一番早いです。棒の根元はキャラクターに固定され、マウスはその棒を回す役目になります。
マウスの X は棒を水平方向に回し(yaw)、マウスの Y はそれを上下に振ります(pitch)。
回すためのリグを組む
using UnityEngine;
public class OrbitCamera : MonoBehaviour
{
[SerializeField] private Transform target; // the Knight's CameraTarget child, from tab 02
[SerializeField] private float distance = 6f;
[SerializeField] private float sensitivity = 240f;
[SerializeField] private float minPitch = -25f;
[SerializeField] private float maxPitch = 65f;
[SerializeField] private LayerMask obstacles;
private float yaw;
private float pitch = 20f;
void Start()
{
Cursor.lockState = CursorLockMode.Locked; // hide and centre the cursor
Cursor.visible = false;
}
void LateUpdate()
{
// ---- 1. accumulate the angles
yaw += Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
pitch -= Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime;
pitch = Mathf.Clamp(pitch, minPitch, maxPitch); // never flip over
// ---- 2. build the rotation, then push back along -Z
Quaternion rot = Quaternion.Euler(pitch, yaw, 0f);
Vector3 pivot = target.position;
Vector3 wanted = pivot + rot * new Vector3(0f, 0f, -distance);
// ---- 3. pull in if a wall is in the way
float realDistance = distance;
if (Physics.SphereCast(pivot, 0.3f, (wanted - pivot).normalized,
out RaycastHit hit, distance, obstacles))
realDistance = hit.distance - 0.2f;
transform.position = pivot + rot * new Vector3(0f, 0f, -realDistance);
transform.rotation = rot;
}
public float Yaw => yaw; // movement uses this to know 'forward'
}Unity では pitch が正の値だとカメラが下を向くため、pitch -= mouseY にしています。引き算にすると、定番の「マウスを手前に押す=見上げる」という手感になります。
pitch をクランプするのは省略できません。上限を設けないとカメラが頭の上を通過し、世界がひっくり返ります。
rot * new Vector3(0, 0, -distance) がこの仕組みの核心です。後ろ向きのベクトルを回転させれば、それがそのままカメラの位置になります。
移動処理に接続する
PlayerMovement はすでに Camera.main.transform.eulerAngles.y を読んでいるので、このカメラは付けた瞬間から正しく動きます。つまり「前」は、このカメラから遠ざかる方向になります。
誤差のないマウス感度
- 1
Mouse X/Y はすでにフレームごとの差分なので、Time.deltaTime を掛けるのは厳密には間違いです。ただし Inspector の数値がフレームレートに左右されずに安定するという利点もあります。流儀を一つ決めて、そこへ揃えてください。
- 2
感度は設定メニューから変更できるように公開してください。プレイヤーの数だけマウスの DPI が違います。
- 3
Y 軸を反転するトグルも追加しておいてください。五人に一人は必ず必要とし、それが無いままならゲームを離れてしまいます。
if (Input.GetKeyDown(KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}よくあるミス
yaw と pitch を transform.eulerAngles に保存して読み戻すとクランプが壊れます。Unity は角度を 0~360 に丸めるので、pitch が -10 ではなく 350 として読めてしまうからです。二つの角度は自前の float フィールドに持ってください。
メニュー用や Cinemachine が作った二台目のカメラにも MainCamera タグが付いていると、Camera.main は先に見つかった方を返し、前方向が反転します。MainCamera タグは一つだけにするか、代わりにこのスクリプトの Yaw を読んでください。
obstacles を Nothing のままにすると SphereCast は何にも当たらず、カメラは相変わらず壁を抜けます。ステージのジオメトリのレイヤーを指定してください。Player レイヤーは絶対に含めないこと。含めるとカメラがキャラクター自身の後ろに隠れてしまいます。