using UnityEngine; [DisallowMultipleComponent] public sealed class MapCrosshairController : MonoBehaviour { [Header("Nearest Target (Runtime)")] [SerializeField] private MapTarget nearestTarget; [SerializeField] private float distanceToNearestTarget = -1f; private MapCoordinateSystem coordinateSystem; private MapTargetController targetController; private Transform relayX; private Transform relayY; private Transform crosshairVisual; private Vector2 crosshairCoordinates; private Vector3 relayXOffset; private Vector3 relayYOffset; private bool isConfigured; public MapCoordinateSystem CoordinateSystem => coordinateSystem; public Vector2 Coordinates => crosshairCoordinates; public void Configure( MapCoordinateSystem newCoordinateSystem, Transform newRelayX, Transform newRelayY, Transform newCrosshairVisual, MapTargetController newTargetController) { coordinateSystem = newCoordinateSystem; relayX = newRelayX; relayY = newRelayY; crosshairVisual = newCrosshairVisual; targetController = newTargetController; isConfigured = CalibrateObjects(); } public void SetCoordinates(Vector2 coordinates) { if (!isConfigured) return; crosshairCoordinates = coordinateSystem.ClampCoordinates(coordinates); ApplyCoordinates(); UpdateNearestTarget(); } public Vector2 GetCrosshairCoordinates() => crosshairCoordinates; public MapTarget GetNearestTarget() => nearestTarget; public float GetDistanceToNearestTarget() => distanceToNearestTarget; public bool TryGetNearestTarget(out MapTarget target, out float distance) { target = nearestTarget; distance = distanceToNearestTarget; return target != null; } private void ApplyCoordinates() { crosshairVisual.position = coordinateSystem.CoordinatesToWorldPosition(crosshairCoordinates); 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); } }