using System; using System.Collections.Generic; using GeometryTD.UI; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.Tilemaps; namespace GeometryTD.Entity { public sealed class CombatSelectInputService { public bool TryBuildUserData( Tilemap tilemap, Transform mapTransform, IReadOnlyDictionary towerEntityIdByFoundationCell, Func isFoundationCell, Func isTowerAtMaxLevel, int upgradeCost, int destroyGain, out CombatSelectFormUserData userData) { userData = null; if (tilemap == null || !TryGetPointerWorldPosition(tilemap, mapTransform, out Vector3 worldPosition, out Vector2 screenPosition)) { return false; } Vector3Int clickedCell = tilemap.WorldToCell(worldPosition); CombatSelectClickObjectType clickObjectType = CombatSelectClickObjectType.None; int towerEntityId = 0; Vector2 resolvedScreenPosition = screenPosition; if (towerEntityIdByFoundationCell != null && towerEntityIdByFoundationCell.TryGetValue(clickedCell, out int occupiedTowerEntityId)) { clickObjectType = CombatSelectClickObjectType.Tower; towerEntityId = occupiedTowerEntityId; resolvedScreenPosition = BuildScreenPositionFromCell(tilemap, clickedCell, screenPosition); } else if (isFoundationCell != null && isFoundationCell(clickedCell)) { clickObjectType = CombatSelectClickObjectType.Foundation; resolvedScreenPosition = BuildScreenPositionFromCell(tilemap, clickedCell, screenPosition); } userData = new CombatSelectFormUserData { ClickObjectType = clickObjectType, ScreenPosition = resolvedScreenPosition, WorldPosition = worldPosition, CellPosition = clickedCell, TowerEntityId = towerEntityId, IsTowerAtMaxLevel = towerEntityId != 0 && isTowerAtMaxLevel != null && isTowerAtMaxLevel(towerEntityId), UpgradeCost = Mathf.Max(0, upgradeCost), DestroyGain = Mathf.Max(0, destroyGain) }; return true; } private static bool TryGetPointerWorldPosition(Tilemap tilemap, Transform mapTransform, out Vector3 worldPosition, out Vector2 screenPosition) { worldPosition = Vector3.zero; screenPosition = Vector2.zero; Camera mainCamera = GameEntry.Scene != null ? GameEntry.Scene.MainCamera : Camera.main; if (mainCamera == null) { return false; } Mouse mouse = Mouse.current; if (mouse == null) { return false; } Vector2 pointerPosition = mouse.position.ReadValue(); Ray ray = mainCamera.ScreenPointToRay(pointerPosition); float mapPlaneZ = tilemap != null ? tilemap.transform.position.z : (mapTransform != null ? mapTransform.position.z : 0f); Vector3 planeNormal = mainCamera.transform.forward.sqrMagnitude > Mathf.Epsilon ? -mainCamera.transform.forward : Vector3.forward; Plane mapPlane = new Plane(planeNormal, new Vector3(0f, 0f, mapPlaneZ)); if (!mapPlane.Raycast(ray, out float enterDistance)) { return false; } worldPosition = ray.GetPoint(enterDistance); screenPosition = BuildScreenPosition(pointerPosition); return true; } private static Vector2 BuildScreenPosition(Vector3 pointerScreenPosition) { return new Vector2(pointerScreenPosition.x, pointerScreenPosition.y); } private static Vector2 BuildScreenPositionFromCell(Tilemap tilemap, Vector3Int cellPosition, Vector2 fallbackScreenPosition) { if (tilemap == null) { return fallbackScreenPosition; } Camera mainCamera = GameEntry.Scene != null ? GameEntry.Scene.MainCamera : Camera.main; if (mainCamera == null) { return fallbackScreenPosition; } Vector3 cellCenterWorld = tilemap.GetCellCenterWorld(cellPosition); Vector3 cellScreenPosition = mainCamera.WorldToScreenPoint(cellCenterWorld); if (cellScreenPosition.z < 0f) { return fallbackScreenPosition; } return BuildScreenPosition(cellScreenPosition); } } }