291 lines
9.8 KiB
C#
291 lines
9.8 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
|
|
namespace UVC.Simulator
|
|
{
|
|
enum CamState
|
|
{
|
|
fly,
|
|
topView
|
|
}
|
|
public class FirstPersonCamera : MonoBehaviour
|
|
{
|
|
[Header("Fly")]
|
|
[SerializeField] private float move3DSpeed = 10f;
|
|
[SerializeField] private float rotate3DSpeed = 100f;
|
|
[SerializeField] private float zoom3DSpeed = 500f;
|
|
|
|
[SerializeField] private float camera3DXMin = -50f;
|
|
[SerializeField] private float camera3DXMax = 50f;
|
|
[SerializeField] private float camera3DYMin = 2f;
|
|
[SerializeField] private float camera3DYMax = 40f;
|
|
[SerializeField] private float camera3DZMin = -50f;
|
|
[SerializeField] private float camera3DZMax = 50f;
|
|
|
|
[SerializeField] private float camera3DZoomMin = 35f;
|
|
[SerializeField] private float camera3DZoomMax = 90f;
|
|
|
|
[SerializeField] private float camera3DRotateMin = -90f;
|
|
[SerializeField] private float camera3DRotateMax = 90f;
|
|
|
|
[Header("Top View")]
|
|
[SerializeField] private float topViewPanSpeed = 10f;
|
|
[SerializeField] private float topViewQEVerticalSpeed = 5f;
|
|
[SerializeField] private float topViewOrthoSize = 20f;
|
|
[SerializeField] private KeyCode toggleTopViewKey = KeyCode.Tab;
|
|
|
|
private Vector3 initial3DRotation;
|
|
private Vector3 initial3DPosition;
|
|
private float initialFOV = 60f;
|
|
|
|
private Coroutine cameraMoveCoroutine;
|
|
private float timeCameraChange = 1f;
|
|
private Vector3 topViewPosition = new Vector3(-4f, 16f, 1f);
|
|
private readonly Vector3 topViewRotation = new Vector3(90f, 0f, 0f);
|
|
private CamState CamState = CamState.fly;
|
|
|
|
float CameraSpeedAlpha = 0f;
|
|
|
|
Vector3 offSet = new Vector3(0f, 0f, 0f);
|
|
private GameObject target;
|
|
public GameObject Target => target;
|
|
|
|
private Camera cam;
|
|
private Vector3 lastMousePos;
|
|
|
|
private void Start()
|
|
{
|
|
cam = Camera.main;
|
|
cam.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, (camera3DZoomMax + camera3DZoomMin) / 2, 0.05f);
|
|
initial3DPosition = transform.position;
|
|
initial3DRotation = transform.eulerAngles;
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
Zoom3DCamera();
|
|
if (CamState == CamState.fly)
|
|
{
|
|
Rotate3DCamera();
|
|
MoveKeyBoard();
|
|
}
|
|
else
|
|
{
|
|
PanningCamera();
|
|
}
|
|
}
|
|
|
|
private void MoveKeyBoard()
|
|
{
|
|
float x = Input.GetAxisRaw("Horizontal");
|
|
float z = Input.GetAxisRaw("Vertical");
|
|
Move3DCamera(x, z);
|
|
}
|
|
|
|
private void Move3DCamera(float x, float z)
|
|
{
|
|
Vector3 moveVector = new Vector3(x, 0, z);
|
|
|
|
if (Input.GetKey(KeyCode.Q))
|
|
{
|
|
moveVector += Vector3.down;
|
|
}
|
|
else if (Input.GetKey(KeyCode.E))
|
|
{
|
|
moveVector += Vector3.up;
|
|
}
|
|
transform.Translate(moveVector * move3DSpeed * Time.deltaTime);
|
|
|
|
Vector3 p = transform.position;
|
|
p.x = Mathf.Clamp(p.x, camera3DXMin, camera3DXMax);
|
|
p.y = Mathf.Clamp(p.y, camera3DYMin, camera3DYMax);
|
|
p.z = Mathf.Clamp(p.z, camera3DZMin, camera3DZMax);
|
|
transform.position = p;
|
|
}
|
|
|
|
|
|
void Rotate3DCamera()
|
|
{
|
|
if (Input.GetMouseButton(2))
|
|
{
|
|
float xRotationInput = -Input.GetAxis("Mouse Y");
|
|
float yRotationInput = Input.GetAxis("Mouse X");
|
|
|
|
Vector3 newRotation = transform.localEulerAngles + new Vector3(xRotationInput, yRotationInput, 0f) * rotate3DSpeed * Time.deltaTime;
|
|
float clampedXRotation = ClampAngle(newRotation.x, camera3DRotateMin, camera3DRotateMax);
|
|
|
|
newRotation.x = clampedXRotation;
|
|
newRotation.z = 0f;
|
|
|
|
transform.localEulerAngles = newRotation;
|
|
}
|
|
}
|
|
|
|
public void EnterTopView()
|
|
{
|
|
CamState = CamState.topView;
|
|
if (cam == null) cam = Camera.main != null ? Camera.main : GetComponent<Camera>();
|
|
|
|
if (cam != null)
|
|
{
|
|
// Projection 전환
|
|
cam.orthographic = true;
|
|
cam.orthographicSize = topViewOrthoSize;
|
|
}
|
|
|
|
// 회전/위치(진입 시 각도 고정, 위치는 유지. 필요 시 고정 좌표로 이동하려면 주석 해제)
|
|
transform.rotation = Quaternion.Euler(topViewRotation);
|
|
// transform.position = new Vector3(transform.position.x, Mathf.Max(transform.position.y, camera3DYMin), transform.position.z);
|
|
}
|
|
|
|
public void ExitTopView()
|
|
{
|
|
CamState = CamState.fly;
|
|
if (cam == null) cam = Camera.main != null ? Camera.main : GetComponent<Camera>();
|
|
|
|
if (cam != null)
|
|
{
|
|
cam.orthographic = false;
|
|
//cam.fieldOfView = Mathf.Clamp(initialFOV, camera3DZoomMin, camera3DZoomMax);
|
|
}
|
|
}
|
|
public void ToggleTopView()
|
|
{
|
|
if (CamState == CamState.topView) ExitTopView();
|
|
else EnterTopView();
|
|
}
|
|
|
|
void PanningCamera()
|
|
{
|
|
float x = Input.GetAxisRaw("Horizontal");
|
|
float z = Input.GetAxisRaw("Vertical");
|
|
if (Mathf.Abs(x) > 0.001f || Mathf.Abs(z) > 0.001f)
|
|
{
|
|
Vector3 pan = (transform.right * x + transform.up * z) * topViewPanSpeed * Time.deltaTime;
|
|
transform.position += new Vector3(pan.x, 0f, pan.z);
|
|
}
|
|
|
|
if (Input.GetMouseButtonDown(2))
|
|
lastMousePos = Input.mousePosition;
|
|
|
|
if (Input.GetMouseButton(2))
|
|
{
|
|
Vector3 delta = Input.mousePosition - lastMousePos;
|
|
lastMousePos = Input.mousePosition;
|
|
|
|
Vector3 dragPan = (-transform.right * delta.x - transform.up * delta.y) * (topViewPanSpeed / 200f);
|
|
transform.position += new Vector3(dragPan.x, 0f, dragPan.z);
|
|
}
|
|
|
|
transform.rotation = Quaternion.Euler(topViewRotation);
|
|
}
|
|
|
|
private float ClampAngle(float angle, float min, float max)
|
|
{
|
|
angle = NormalizeAngle(angle);
|
|
if (angle > 180f) angle -= 360f;
|
|
return Mathf.Clamp(angle, min, max);
|
|
}
|
|
|
|
private float NormalizeAngle(float angle)
|
|
{
|
|
while (angle > 360f) angle -= 360f;
|
|
while (angle < 0f) angle += 360f;
|
|
return angle;
|
|
}
|
|
|
|
private void Zoom3DCamera()
|
|
{
|
|
if (cam == null) return;
|
|
float z = -Input.GetAxis("Mouse ScrollWheel") * zoom3DSpeed * Time.deltaTime;
|
|
cam.fieldOfView = Mathf.Clamp(cam.fieldOfView + z, camera3DZoomMin, camera3DZoomMax);
|
|
}
|
|
|
|
#region movetotarget
|
|
private void ResetToPosition(int mode)
|
|
{
|
|
transform.parent = null;
|
|
offSet = Vector3.zero;
|
|
if (cameraMoveCoroutine != null) StopCoroutine(cameraMoveCoroutine);
|
|
|
|
if (mode == 0)
|
|
{
|
|
cameraMoveCoroutine = StartCoroutine(MoveToTarget(null, initial3DPosition, Quaternion.Euler(initial3DRotation)));
|
|
ResetZoom();
|
|
}
|
|
else if (mode == 1)
|
|
{
|
|
cameraMoveCoroutine = StartCoroutine(MoveToTarget(null, topViewPosition, Quaternion.Euler(topViewRotation)));
|
|
ResetZoom();
|
|
}
|
|
}
|
|
|
|
private void MoveCameraToObject(GameObject target)
|
|
{
|
|
ResetZoom();
|
|
if (cameraMoveCoroutine != null) StopCoroutine(cameraMoveCoroutine);
|
|
|
|
this.target = target;
|
|
|
|
if (target != null)
|
|
{
|
|
cameraMoveCoroutine = StartCoroutine(MoveToTarget(target, target.transform.position, target.transform.rotation));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
private IEnumerator MoveToTarget(GameObject target, Vector3 pos, Quaternion rot)
|
|
{
|
|
if (cam == null) yield break;
|
|
|
|
Vector3 targetPosition = pos + offSet;
|
|
Vector3 startPosition = cam.transform.position;
|
|
Quaternion startRotation = cam.transform.rotation;
|
|
Quaternion targetRotation = (target != null)
|
|
? Quaternion.LookRotation(pos - targetPosition + new Vector3(0f, 1f, 0f))
|
|
: rot;
|
|
|
|
float elapsedTime = 0f;
|
|
CameraSpeedAlpha = 0f;
|
|
|
|
while (elapsedTime < timeCameraChange)
|
|
{
|
|
cam.transform.position = Vector3.Lerp(startPosition, targetPosition, elapsedTime / timeCameraChange);
|
|
cam.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, elapsedTime / timeCameraChange);
|
|
|
|
CameraSpeedAlpha += 0.001f;
|
|
elapsedTime += Time.deltaTime * CameraSpeedAlpha;
|
|
yield return null;
|
|
}
|
|
|
|
cam.transform.position = targetPosition;
|
|
cam.transform.rotation = targetRotation;
|
|
|
|
cameraMoveCoroutine = null;
|
|
}
|
|
|
|
public void ResetZoom()
|
|
{
|
|
StartCoroutine(ZoomOut());
|
|
}
|
|
|
|
private IEnumerator ZoomOut()
|
|
{
|
|
if (cam == null) yield break;
|
|
|
|
float startZoom = cam.fieldOfView;
|
|
float targetZoom = (camera3DZoomMax + camera3DZoomMin) / 2f;
|
|
float elapsedTime = 0f;
|
|
CameraSpeedAlpha = 0f;
|
|
|
|
while (elapsedTime < timeCameraChange)
|
|
{
|
|
cam.fieldOfView = Mathf.Lerp(startZoom, targetZoom, elapsedTime / timeCameraChange);
|
|
|
|
CameraSpeedAlpha += 0.01f;
|
|
elapsedTime += Time.deltaTime * CameraSpeedAlpha;
|
|
yield return null;
|
|
}
|
|
}
|
|
}
|
|
} |