using UnityEngine; using UnityEngine.InputSystem; public class CameraController : MonoBehaviour { // Zoom settings public float minZoom = 5f; public float maxZoom = 25f; public float zoomSpeed = 2f; public float pinchZoomSpeed = 0.1f; // Pan settings public float panSpeed = 1f; Camera cam; Vector2 lastPanPosition; bool isPanning; float lastPinchDistance; bool isPinching; // Track if we started on a unit (don't pan if drawing route) bool startedOnUnit; void Start() { cam = Camera.main; } void Update() { HandleMouseInput(); HandleTouchInput(); ClampCameraPosition(); } void HandleMouseInput() { var mouse = Mouse.current; if (mouse == null) return; // Scroll wheel zoom float scroll = mouse.scroll.ReadValue().y; if (Mathf.Abs(scroll) > 0.01f) { Zoom(-scroll * zoomSpeed * Time.deltaTime * 10f); } // Right-click pan (left-click is for route drawing) if (mouse.rightButton.wasPressedThisFrame) { lastPanPosition = mouse.position.ReadValue(); isPanning = true; } else if (mouse.rightButton.wasReleasedThisFrame) { isPanning = false; } if (isPanning && mouse.rightButton.isPressed) { Vector2 currentPos = mouse.position.ReadValue(); Vector2 delta = currentPos - lastPanPosition; Pan(-delta); lastPanPosition = currentPos; } } void HandleTouchInput() { var touch = Touchscreen.current; if (touch == null) return; int touchCount = 0; foreach (var t in touch.touches) { if (t.press.isPressed) touchCount++; } if (touchCount == 2) { // Two finger pinch zoom and pan var touch0 = touch.touches[0]; var touch1 = touch.touches[1]; Vector2 pos0 = touch0.position.ReadValue(); Vector2 pos1 = touch1.position.ReadValue(); float currentDistance = Vector2.Distance(pos0, pos1); if (!isPinching) { isPinching = true; lastPinchDistance = currentDistance; lastPanPosition = (pos0 + pos1) / 2f; } else { // Pinch zoom float deltaDistance = lastPinchDistance - currentDistance; Zoom(deltaDistance * pinchZoomSpeed); lastPinchDistance = currentDistance; // Two-finger pan Vector2 currentCenter = (pos0 + pos1) / 2f; Vector2 delta = currentCenter - lastPanPosition; Pan(-delta); lastPanPosition = currentCenter; } isPanning = false; // Don't single-finger pan while pinching } else if (touchCount == 1) { isPinching = false; var primaryTouch = touch.primaryTouch; Vector2 touchPos = primaryTouch.position.ReadValue(); // Check if touch started on a unit if (primaryTouch.press.wasPressedThisFrame) { Vector2 worldPos = cam.ScreenToWorldPoint(touchPos); var hit = Physics2D.OverlapPoint(worldPos); startedOnUnit = hit != null && hit.GetComponent() != null; if (!startedOnUnit) { lastPanPosition = touchPos; isPanning = true; } } else if (primaryTouch.press.wasReleasedThisFrame) { isPanning = false; startedOnUnit = false; } // Single finger pan (only if not drawing route) if (isPanning && !startedOnUnit && primaryTouch.press.isPressed) { Vector2 delta = touchPos - lastPanPosition; Pan(-delta); lastPanPosition = touchPos; } } else { isPinching = false; isPanning = false; } } void Zoom(float delta) { float newSize = cam.orthographicSize + delta; cam.orthographicSize = Mathf.Clamp(newSize, minZoom, maxZoom); } void Pan(Vector2 screenDelta) { // Convert screen delta to world delta float worldUnitsPerPixel = cam.orthographicSize * 2f / Screen.height; Vector3 worldDelta = new Vector3( screenDelta.x * worldUnitsPerPixel * panSpeed, screenDelta.y * worldUnitsPerPixel * panSpeed, 0 ); cam.transform.position += worldDelta; } void ClampCameraPosition() { // Keep camera within map bounds (with some padding for zoom) float halfHeight = cam.orthographicSize; float halfWidth = halfHeight * cam.aspect; float minX = -Game.MapWidth / 2f + halfWidth; float maxX = Game.MapWidth / 2f - halfWidth; float minY = -Game.MapHeight / 2f + halfHeight; float maxY = Game.MapHeight / 2f - halfHeight; Vector3 pos = cam.transform.position; pos.x = Mathf.Clamp(pos.x, minX, maxX); pos.y = Mathf.Clamp(pos.y, minY, maxY); cam.transform.position = pos; } }