212 lines
6.7 KiB
C#
212 lines
6.7 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
|
|
public class CameraControl : MonoBehaviour
|
|
{
|
|
[Header("Dependencies")]
|
|
private BaseInputProvider inputProvider;
|
|
|
|
[Header("Settings")]
|
|
public Transform pivotPoint;
|
|
public LayerMask obstacleLayer;
|
|
|
|
[Header("Speeds")]
|
|
public float panSpeed = 0.5f;
|
|
public float rotateSpeed = 5.0f;
|
|
public float zoomSpeed = 5.0f;
|
|
public float minZoom = 2.0f;
|
|
public float maxZoom = 50.0f;
|
|
|
|
[Header("Smoothness")]
|
|
public bool enableSmoothing = true;
|
|
public float smoothTime = 0.1f;
|
|
|
|
// ---- Internal State ----
|
|
private Vector3 _targetPosition;
|
|
private Quaternion _targetRotation;
|
|
private float _targetZoom;
|
|
private Vector3 _currentVelocity;
|
|
|
|
private bool _isPanning;
|
|
private bool _isOrbiting;
|
|
private Vector2 _cursorScreenPos; // kept up to date by OnCursorMoved
|
|
|
|
private Camera _cam;
|
|
|
|
public bool isInputLocked = false;
|
|
|
|
private bool isInitialized = false;
|
|
|
|
// -------------------------------------------------------
|
|
// Lifecycle
|
|
// -------------------------------------------------------
|
|
|
|
private void Start()
|
|
{
|
|
_cam = GetComponent<Camera>();
|
|
if (pivotPoint == null)
|
|
{
|
|
var pivotObj = new GameObject("CameraPivot");
|
|
pivotObj.transform.position = transform.position + transform.forward * 10f;
|
|
pivotPoint = pivotObj.transform;
|
|
}
|
|
|
|
_targetPosition = pivotPoint.position;
|
|
_targetRotation = pivotPoint.rotation;
|
|
_targetZoom = Vector3.Distance(transform.position, pivotPoint.position);
|
|
|
|
inputProvider = InputProviderManager.getInstance()?.getCurrentInputProvider();
|
|
|
|
inputProvider.OnCursorMoved.AddListener(OnCursorMoved);
|
|
inputProvider.OnCursorDelta.AddListener(OnCursorDelta);
|
|
inputProvider.OnPanStart.AddListener(OnPanStart);
|
|
inputProvider.OnPanEnd.AddListener(OnPanEnd);
|
|
inputProvider.OnRotateStart.AddListener(OnRotateStart);
|
|
inputProvider.OnRotateEnd.AddListener(OnRotateEnd);
|
|
inputProvider.OnZoom.AddListener(OnZoom);
|
|
|
|
isInitialized = true;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (!isInitialized) return;
|
|
|
|
inputProvider.OnCursorMoved.AddListener(OnCursorMoved);
|
|
inputProvider.OnCursorDelta.AddListener(OnCursorDelta);
|
|
inputProvider.OnPanStart.AddListener(OnPanStart);
|
|
inputProvider.OnPanEnd.AddListener(OnPanEnd);
|
|
inputProvider.OnRotateStart.AddListener(OnRotateStart);
|
|
inputProvider.OnRotateEnd.AddListener(OnRotateEnd);
|
|
inputProvider.OnZoom.AddListener(OnZoom);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
inputProvider.OnCursorMoved.RemoveListener(OnCursorMoved);
|
|
inputProvider.OnCursorDelta.RemoveListener(OnCursorDelta);
|
|
inputProvider.OnPanStart.RemoveListener(OnPanStart);
|
|
inputProvider.OnPanEnd.RemoveListener(OnPanEnd);
|
|
inputProvider.OnRotateStart.RemoveListener(OnRotateStart);
|
|
inputProvider.OnRotateEnd.RemoveListener(OnRotateEnd);
|
|
inputProvider.OnZoom.RemoveListener(OnZoom);
|
|
}
|
|
|
|
private void LateUpdate() => ApplyMovement();
|
|
|
|
// -------------------------------------------------------
|
|
// Input event handlers
|
|
// -------------------------------------------------------
|
|
|
|
private void OnCursorMoved(Vector2 screenPos)
|
|
{
|
|
_cursorScreenPos = screenPos;
|
|
}
|
|
|
|
private void OnPanStart(Vector2 cursorScreenPos)
|
|
{
|
|
if (isInputLocked) return;
|
|
|
|
Ray ray = _cam.ScreenPointToRay(cursorScreenPos);
|
|
_isPanning = !Physics.Raycast(ray, out _, 1000f, obstacleLayer);
|
|
}
|
|
|
|
private void OnPanEnd() => _isPanning = false;
|
|
|
|
private void OnRotateStart()
|
|
{
|
|
if (!isInputLocked) _isOrbiting = true;
|
|
}
|
|
|
|
private void OnRotateEnd() => _isOrbiting = false;
|
|
|
|
private void OnCursorDelta(Vector2 delta)
|
|
{
|
|
if (_isPanning)
|
|
{
|
|
if (!InputModeManager.Is(InputMode.Camera)) return;
|
|
Vector3 move = -transform.right * (delta.x * panSpeed * 0.01f)
|
|
+ -transform.up * (delta.y * panSpeed * 0.01f);
|
|
_targetPosition += move;
|
|
}
|
|
|
|
if (_isOrbiting)
|
|
{
|
|
float mouseX = delta.x * rotateSpeed;
|
|
float mouseY = -delta.y * rotateSpeed;
|
|
|
|
Vector3 euler = _targetRotation.eulerAngles;
|
|
euler.y += mouseX;
|
|
euler.x += mouseY;
|
|
|
|
if (euler.x > 180f) euler.x -= 360f;
|
|
euler.x = Mathf.Clamp(euler.x, -85f, 85f);
|
|
|
|
_targetRotation = Quaternion.Euler(euler);
|
|
}
|
|
}
|
|
|
|
private void OnZoom(float scrollValue)
|
|
{
|
|
if (!InputModeManager.Is(InputMode.Camera)) return;
|
|
|
|
_targetZoom -= scrollValue * zoomSpeed * 0.05f;
|
|
_targetZoom = Mathf.Clamp(_targetZoom, minZoom, maxZoom);
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// Movement application (unchanged logic)
|
|
// -------------------------------------------------------
|
|
|
|
private void ApplyMovement()
|
|
{
|
|
if (enableSmoothing)
|
|
{
|
|
pivotPoint.position = Vector3.SmoothDamp(
|
|
pivotPoint.position, _targetPosition, ref _currentVelocity, smoothTime);
|
|
|
|
pivotPoint.rotation = Quaternion.Slerp(
|
|
pivotPoint.rotation, _targetRotation, Time.deltaTime * (1f / smoothTime));
|
|
}
|
|
else
|
|
{
|
|
pivotPoint.position = _targetPosition;
|
|
pivotPoint.rotation = _targetRotation;
|
|
}
|
|
|
|
transform.position = pivotPoint.position - pivotPoint.forward * _targetZoom;
|
|
transform.LookAt(pivotPoint);
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// Public API
|
|
// -------------------------------------------------------
|
|
|
|
public void SnapToDirection(Vector3 direction)
|
|
{
|
|
Vector3 cameraUp = Mathf.Abs(Vector3.Dot(direction, Vector3.up)) > 0.99f
|
|
? Vector3.forward
|
|
: Vector3.up;
|
|
|
|
_targetRotation = Quaternion.LookRotation(direction, cameraUp);
|
|
_targetPosition = pivotPoint.position;
|
|
_currentVelocity = Vector3.zero;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// Gizmos
|
|
// -------------------------------------------------------
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (pivotPoint == null) return;
|
|
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawWireSphere(pivotPoint.position, 0.5f);
|
|
Gizmos.DrawLine(transform.position, pivotPoint.position);
|
|
|
|
Gizmos.color = Color.cyan;
|
|
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
|
Gizmos.DrawFrustum(Vector3.zero, GetComponent<Camera>().fieldOfView, maxZoom, minZoom, 1.0f);
|
|
}
|
|
} |