본문 바로가기
Game Engine/Unity

(Unity) 기본적인 Spectator Camera

by MeisterTJ 2022. 7. 20.

Scene 테스트를 할 때 사용하기 유용한 Spectator Camera 코드이다.

 

Main Camera에 추가해서 사용하면 된다. 

 

using UnityEngine;

public class SpectatorController : MonoBehaviour
{
    [Header("Sensitivity")]
    public float sensitivityX;
    public float sensitivityY;

    [Header("X Axis Rotation Min, Max")]
    public float minX;

    public float maxX;

    [Header("Move Speed")]
    public float moveSpeed;

    private bool bCursorLocked = false;
    
    private float rotX;
    private float rotY;

    private float moveSpeedMin = 1f;
    private float moveSpeedMax = 50f;

    void Start()
    {
        // 최초 카메라의 rotation 상태 저장
        rotX = -transform.rotation.eulerAngles.x;
        rotY = transform.rotation.eulerAngles.y;
    }

    private void Update()
    {
        // 매 Update시 Lock 상태 업데이트
        InternalLockUpdate();
    }

    private void LateUpdate()
    {
        if (!bCursorLocked) return; 
        
        // 마우스 좌우 움직임  -> y축 회전
        // 마우스 위아래 움직임 -> x축 회전
        rotY += Input.GetAxis("Mouse X") * sensitivityX;
        rotX += Input.GetAxis("Mouse Y") * sensitivityY;

        rotX = Mathf.Clamp(rotX, minX, maxX);

        // Mouse Wheel -> Move Speed
        Vector2 wheelDelta = Input.mouseScrollDelta;

        if (wheelDelta.y > 0 || wheelDelta.y < 0)
        {
            moveSpeed = Mathf.Clamp(moveSpeed + wheelDelta.y, moveSpeedMin, moveSpeedMax);
        }

        // Key Input
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        float y = 0;

        if (Input.GetKey(KeyCode.E))
        {
            y = 1;
        }
        else if (Input.GetKey(KeyCode.Q))
        {
            y = -1;
        }
        
        var transformRef = transform;
        Vector3 dir = transformRef.right * x + transformRef.up * y + transformRef.forward * z;
        transformRef.rotation = Quaternion.Euler(-rotX, rotY, 0);
        transformRef.position += dir * (moveSpeed * Time.deltaTime);
    }

    private void InternalLockUpdate()
    {
#if UNITY_EDITOR
        if (Input.GetKeyUp(KeyCode.Escape))
        {
            bCursorLocked = false;
        }
        else if (Input.GetMouseButtonUp(0))
        {
            bCursorLocked = true;
        }
#endif

        if (bCursorLocked)
        {
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
        }
        else
        {
            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
        }
    }
}

InternalLockUpdate는 Unity의 first person character의 코드와 거의 같은 부분인데,

화면 클릭 상태에서는 커서를 잠그고, escape를 하면 커서를 풀어주는 함수이다. 

 

Escape 키 입력을 받지 않아도 editor 상에서 esc를 누르면 cursor의 lock 상태가 풀리는데, 

문제는 이 경우 Cursor.lockState 및 Cursor.visible 상태는 바뀌지 않기 때문에 lock이 풀렸는지 아닌지 알 수가 없다.

 

그렇기 때문에 수동으로 제어해야 한다.