using UnityEngine;
using UnityEngine.InputSystem;
///
/// Simple camera movement controller for map navigation.
/// Supports WASD/arrow keys, right-click drag, and Q/E or mouse wheel zoom.
///
[RequireComponent(typeof(Camera))]
public class MazeCameraController : MonoBehaviour
{
[Header("Movement")]
[SerializeField] private float moveSpeed = 20f;
[SerializeField] private float dragSpeed = 1f;
[Header("Zoom")]
[SerializeField] private float zoomSpeed = 25f;
[SerializeField] private float zoomMin = 5f;
[SerializeField] private float zoomMax = 120f;
[Header("Optional Bounds")]
[SerializeField] private bool useBounds = false;
[SerializeField] private Vector2 minBounds = new Vector2(-100f, -100f);
[SerializeField] private Vector2 maxBounds = new Vector2(100f, 100f);
private Camera cameraComponent;
private Vector3 targetPosition;
private Vector3 lastMousePosition;
private bool isDragging;
private void Awake()
{
cameraComponent = GetComponent();
targetPosition = transform.position;
}
private void Update()
{
HandleKeyboardMovement();
HandleMouseDrag();
HandleZoom();
ApplyPosition();
}
private void HandleKeyboardMovement()
{
var keyboard = Keyboard.current;
if (keyboard == null)
{
return;
}
float horizontal = 0f;
if (keyboard.aKey.isPressed || keyboard.leftArrowKey.isPressed)
{
horizontal -= 1f;
}
if (keyboard.dKey.isPressed || keyboard.rightArrowKey.isPressed)
{
horizontal += 1f;
}
float vertical = 0f;
if (keyboard.sKey.isPressed || keyboard.downArrowKey.isPressed)
{
vertical -= 1f;
}
if (keyboard.wKey.isPressed || keyboard.upArrowKey.isPressed)
{
vertical += 1f;
}
if (horizontal != 0f || vertical != 0f)
{
Vector3 right = transform.right;
Vector3 forward = Vector3.Cross(transform.right, Vector3.up).normalized;
Vector3 worldMove = (right * horizontal + forward * vertical).normalized;
targetPosition += worldMove * moveSpeed * Time.deltaTime;
}
if (keyboard.qKey.isPressed)
{
Zoom(-zoomSpeed * Time.deltaTime);
}
else if (keyboard.eKey.isPressed)
{
Zoom(zoomSpeed * Time.deltaTime);
}
}
private void HandleMouseDrag()
{
var mouse = Mouse.current;
if (mouse == null)
{
return;
}
if (mouse.rightButton.wasPressedThisFrame)
{
isDragging = true;
Vector2 position = mouse.position.ReadValue();
lastMousePosition = new Vector3(position.x, position.y, 0f);
}
if (mouse.rightButton.wasReleasedThisFrame)
{
isDragging = false;
}
if (isDragging && mouse.rightButton.isPressed)
{
Vector2 position = mouse.position.ReadValue();
Vector3 currentMousePosition = new Vector3(position.x, position.y, 0f);
if (currentMousePosition != lastMousePosition)
{
Vector3 dragDelta = GetDragWorldDelta(lastMousePosition, currentMousePosition);
targetPosition += dragDelta * dragSpeed;
lastMousePosition = currentMousePosition;
}
}
}
private void HandleZoom()
{
var mouse = Mouse.current;
if (mouse != null)
{
float scroll = mouse.scroll.ReadValue().y;
if (scroll != 0f)
{
Zoom(-scroll * zoomSpeed * Time.deltaTime);
}
}
}
private void Zoom(float amount)
{
if (cameraComponent.orthographic)
{
cameraComponent.orthographicSize = Mathf.Clamp(cameraComponent.orthographicSize + amount, zoomMin, zoomMax);
}
else
{
cameraComponent.fieldOfView = Mathf.Clamp(cameraComponent.fieldOfView + amount, zoomMin, zoomMax);
}
}
private Vector3 GetDragWorldDelta(Vector3 previousScreenPosition, Vector3 currentScreenPosition)
{
Plane dragPlane = new Plane(-transform.forward, transform.position);
Ray previousRay = cameraComponent.ScreenPointToRay(previousScreenPosition);
Ray currentRay = cameraComponent.ScreenPointToRay(currentScreenPosition);
if (dragPlane.Raycast(previousRay, out float previousDistance) && dragPlane.Raycast(currentRay, out float currentDistance))
{
Vector3 previousWorld = previousRay.GetPoint(previousDistance);
Vector3 currentWorld = currentRay.GetPoint(currentDistance);
return previousWorld - currentWorld;
}
return Vector3.zero;
}
private void ApplyPosition()
{
Vector3 newPosition = targetPosition;
if (useBounds)
{
newPosition.x = Mathf.Clamp(newPosition.x, minBounds.x, maxBounds.x);
newPosition.z = Mathf.Clamp(newPosition.z, minBounds.y, maxBounds.y);
}
transform.position = newPosition;
}
}