using UnityEngine; using UnityEngine.InputSystem; [DisallowMultipleComponent] public sealed class MapCrosshairController : MonoBehaviour { [Header("Nearest Target (Runtime)")] [SerializeField] private MapTarget nearestTarget = null; [SerializeField] private float distanceToNearestTarget = -1f; private MapCoordinateSystem coordinateSystem; private MapTargetController targetController; private Transform relayX; private Transform relayY; private Transform crosshairVisual; private float movementSpeed; private bool useKeyboardInput; private float horizontalAxis; private float verticalAxis; private Vector2 crosshairCoordinates; private Vector3 relayXOffset; private Vector3 relayYOffset; private bool isConfigured; public MapCoordinateSystem CoordinateSystem => coordinateSystem; public void Configure( MapCoordinateSystem newCoordinateSystem, Transform newRelayX, Transform newRelayY, Transform newCrosshairVisual, float newMovementSpeed, bool enableKeyboardInput, MapTargetController newTargetController) { coordinateSystem = newCoordinateSystem; relayX = newRelayX; relayY = newRelayY; crosshairVisual = newCrosshairVisual; movementSpeed = Mathf.Max(0f, newMovementSpeed); useKeyboardInput = enableKeyboardInput; targetController = newTargetController; crosshairCoordinates = Vector2.zero; isConfigured = CalibrateObjects(); if (isConfigured) ApplyCoordinates(); } private void Update() { if (!isConfigured) return; if (useKeyboardInput) ReadKeyboardInput(); Vector2 movement = new(horizontalAxis, verticalAxis); crosshairCoordinates += movement * (movementSpeed * Time.deltaTime); crosshairCoordinates = coordinateSystem.ClampCoordinates(crosshairCoordinates); ApplyCoordinates(); UpdateNearestTarget(); } public void SetHorizontalAxis(float value) { horizontalAxis = Mathf.Clamp(value, -1f, 1f); } public void SetVerticalAxis(float value) { verticalAxis = Mathf.Clamp(value, -1f, 1f); } public Vector2 GetCrosshairCoordinates() { return crosshairCoordinates; } public MapTarget GetNearestTarget() { return nearestTarget; } public float GetDistanceToNearestTarget() { return distanceToNearestTarget; } public bool TryGetNearestTarget(out MapTarget target, out float distance) { target = nearestTarget; distance = distanceToNearestTarget; return target != null; } private void ReadKeyboardInput() { Keyboard keyboard = Keyboard.current; if (keyboard == null) { SetHorizontalAxis(0f); SetVerticalAxis(0f); return; } SetHorizontalAxis( (keyboard.lKey.isPressed ? 1f : 0f) - (keyboard.jKey.isPressed ? 1f : 0f)); SetVerticalAxis( (keyboard.iKey.isPressed ? 1f : 0f) - (keyboard.kKey.isPressed ? 1f : 0f)); } private void ApplyCoordinates() { Vector3 targetWorldPosition = coordinateSystem.CoordinatesToWorldPosition(crosshairCoordinates); crosshairVisual.position = targetWorldPosition; if (relayX != null) relayX.position = coordinateSystem.CoordinatesToWorldPosition( new Vector2(crosshairCoordinates.x, 0f)) + relayXOffset; if (relayY != null) relayY.position = coordinateSystem.CoordinatesToWorldPosition( new Vector2(0f, crosshairCoordinates.y)) + relayYOffset; } private bool CalibrateObjects() { if (coordinateSystem == null || crosshairVisual == null || !coordinateSystem.HasValidCorners()) return false; Vector3 origin = coordinateSystem.CoordinatesToWorldPosition(Vector2.zero); Vector3 horizontalDirection = coordinateSystem.CoordinatesToWorldPosition(new Vector2(MapCoordinateSystem.CoordinateMaximum, 0f)) - origin; Vector3 verticalDirection = coordinateSystem.CoordinatesToWorldPosition(new Vector2(0f, MapCoordinateSystem.CoordinateMaximum)) - origin; if (horizontalDirection.sqrMagnitude <= Mathf.Epsilon || verticalDirection.sqrMagnitude <= Mathf.Epsilon) return false; horizontalDirection.Normalize(); verticalDirection.Normalize(); if (relayX != null) relayXOffset = Vector3.ProjectOnPlane(relayX.position - origin, horizontalDirection); if (relayY != null) relayYOffset = Vector3.ProjectOnPlane(relayY.position - origin, verticalDirection); return true; } private void UpdateNearestTarget() { nearestTarget = null; distanceToNearestTarget = -1f; if (targetController == null) return; float nearestSqrDistance = float.PositiveInfinity; foreach (MapTarget target in targetController.Targets) { if (target == null) continue; float sqrDistance = (target.MapCoordinates - crosshairCoordinates).sqrMagnitude; if (sqrDistance >= nearestSqrDistance) continue; nearestSqrDistance = sqrDistance; nearestTarget = target; } if (nearestTarget != null) distanceToNearestTarget = Mathf.Sqrt(nearestSqrDistance); } }