MazeCameraController.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. using UnityEngine;
  2. namespace MazeGen
  3. {
  4. /// <summary>
  5. /// Top-down camera rig: smoothly glides to focus on newly entered rooms, and can be
  6. /// freely panned with WASD or by holding the middle mouse button and dragging. Any
  7. /// manual pan input cancels whatever auto-focus is currently in progress.
  8. /// </summary>
  9. public class MazeCameraController : MonoBehaviour
  10. {
  11. [SerializeField] private float panSpeed = 8f;
  12. [SerializeField] private float focusSharpness = 6f;
  13. [SerializeField] private float dragSensitivity = 1f;
  14. private Camera _camera;
  15. private Vector2? _focusTarget;
  16. private Vector2 _lastPointerScreenPos;
  17. private bool _isDragging;
  18. private void Awake()
  19. {
  20. _camera = GetComponent<Camera>();
  21. if (_camera == null) _camera = Camera.main;
  22. }
  23. /// <summary>Smoothly glides the camera to look at worldPosition.</summary>
  24. public void FocusOn(Vector2 worldPosition)
  25. {
  26. _focusTarget = worldPosition;
  27. }
  28. /// <summary>Instantly moves the camera to worldPosition, no smoothing.</summary>
  29. public void SnapTo(Vector2 worldPosition)
  30. {
  31. _focusTarget = null;
  32. transform.position = new Vector3(worldPosition.x, worldPosition.y, transform.position.z);
  33. }
  34. private void Update()
  35. {
  36. HandleDrag();
  37. HandleKeyboardPan();
  38. HandleAutoFocus();
  39. }
  40. private void HandleKeyboardPan()
  41. {
  42. Vector2 input = MazeInput.ReadWasdAxis();
  43. if (input.sqrMagnitude <= 0f) return;
  44. _focusTarget = null; // manual input takes over from auto-focus
  45. transform.position += new Vector3(input.x, input.y, 0f) * (panSpeed * Time.deltaTime);
  46. }
  47. private void HandleDrag()
  48. {
  49. bool middleHeldNow = MazeInput.IsMiddleMouseHeld();
  50. Vector2 pointerNow = MazeInput.GetPointerScreenPosition();
  51. if (middleHeldNow && !_isDragging)
  52. {
  53. _isDragging = true;
  54. _lastPointerScreenPos = pointerNow;
  55. return;
  56. }
  57. if (middleHeldNow)
  58. {
  59. Vector2 screenDelta = pointerNow - _lastPointerScreenPos;
  60. if (screenDelta.sqrMagnitude > 0f)
  61. {
  62. _focusTarget = null; // manual input takes over from auto-focus
  63. Vector2 worldDelta = ScreenDeltaToWorldDelta(screenDelta);
  64. transform.position -= new Vector3(worldDelta.x, worldDelta.y, 0f);
  65. }
  66. _lastPointerScreenPos = pointerNow;
  67. }
  68. else
  69. {
  70. _isDragging = false;
  71. }
  72. }
  73. private void HandleAutoFocus()
  74. {
  75. if (!_focusTarget.HasValue) return;
  76. Vector2 current = transform.position;
  77. Vector2 target = _focusTarget.Value;
  78. // Framerate-independent exponential smoothing rather than a constant-speed move,
  79. // so the glide eases in and settles instead of arriving abruptly.
  80. float t = 1f - Mathf.Exp(-focusSharpness * Time.deltaTime);
  81. Vector2 next = Vector2.Lerp(current, target, t);
  82. transform.position = new Vector3(next.x, next.y, transform.position.z);
  83. if (Vector2.Distance(next, target) < 0.01f)
  84. _focusTarget = null;
  85. }
  86. private Vector2 ScreenDeltaToWorldDelta(Vector2 screenDelta)
  87. {
  88. if (_camera == null || Screen.height <= 0) return Vector2.zero;
  89. float worldUnitsPerPixel;
  90. if (_camera.orthographic)
  91. {
  92. worldUnitsPerPixel = (_camera.orthographicSize * 2f) / Screen.height;
  93. }
  94. else
  95. {
  96. // Rooms sit on the z = 0 plane; use the camera's distance to it as the
  97. // reference plane for converting a screen-space drag into world units.
  98. float distance = Mathf.Abs(transform.position.z);
  99. worldUnitsPerPixel = (2f * distance * Mathf.Tan(_camera.fieldOfView * 0.5f * Mathf.Deg2Rad)) / Screen.height;
  100. }
  101. return screenDelta * worldUnitsPerPixel * dragSensitivity;
  102. }
  103. }
  104. }