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(); 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().fieldOfView, maxZoom, minZoom, 1.0f); } }