using System; using System.Collections.Generic; using GeometryTD.UI; using UnityEngine; using UnityEngine.Tilemaps; namespace GeometryTD.Entity { public sealed class CombatSelectInputService { public bool TryBuildUserData(Tilemap tilemap, Transform mapTransform, IReadOnlyDictionary towerEntityIdByFoundationCell, Func isFoundationCell, int upgradeCost, int destroyGain, out CombatSelectFormUserData userData) { userData = null; if (tilemap == null || !TryGetPointerWorldPosition(tilemap, mapTransform, out Vector3 worldPosition, out Vector2 contentPosition)) { return false; } Vector3Int clickedCell = tilemap.WorldToCell(worldPosition); CombatSelectClickObjectType clickObjectType = CombatSelectClickObjectType.None; int towerEntityId = 0; Vector2 resolvedContentPosition = contentPosition; if (towerEntityIdByFoundationCell != null && towerEntityIdByFoundationCell.TryGetValue(clickedCell, out int occupiedTowerEntityId)) { clickObjectType = CombatSelectClickObjectType.Tower; towerEntityId = occupiedTowerEntityId; resolvedContentPosition = BuildContentPositionFromCell(tilemap, clickedCell, contentPosition); } else if (isFoundationCell != null && isFoundationCell(clickedCell)) { clickObjectType = CombatSelectClickObjectType.Foundation; resolvedContentPosition = BuildContentPositionFromCell(tilemap, clickedCell, contentPosition); } userData = new CombatSelectFormUserData { ClickObjectType = clickObjectType, ContentPosition = resolvedContentPosition, WorldPosition = worldPosition, CellPosition = clickedCell, TowerEntityId = 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 contentPosition) { worldPosition = Vector3.zero; contentPosition = Vector2.zero; Camera mainCamera = GameEntry.Scene != null ? GameEntry.Scene.MainCamera : Camera.main; if (mainCamera == null) { return false; } Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition); 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); contentPosition = BuildContentPosition(Input.mousePosition); contentPosition = new Vector2((int)contentPosition.x, (int)contentPosition.y); contentPosition = new Vector2(contentPosition.x + 0.5f, contentPosition.y + 0.5f); return true; } private static Vector2 BuildContentPosition(Vector3 pointerScreenPosition) { return new Vector2( pointerScreenPosition.x - Screen.width * 0.5f, pointerScreenPosition.y - Screen.height * 0.5f); } private static Vector2 BuildContentPositionFromCell(Tilemap tilemap, Vector3Int cellPosition, Vector2 fallbackContentPosition) { if (tilemap == null) { return fallbackContentPosition; } Camera mainCamera = GameEntry.Scene != null ? GameEntry.Scene.MainCamera : Camera.main; if (mainCamera == null) { return fallbackContentPosition; } Vector3 cellCenterWorld = tilemap.GetCellCenterWorld(cellPosition); Vector3 cellScreenPosition = mainCamera.WorldToScreenPoint(cellCenterWorld); Vector2 contentPosition = BuildContentPosition(cellScreenPosition); contentPosition = new Vector2((int)contentPosition.x, (int)contentPosition.y); return new Vector2(contentPosition.x + 0.5f, contentPosition.y + 0.5f); } } }