121 lines
4.6 KiB
C#
121 lines
4.6 KiB
C#
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<Vector3Int, int> towerEntityIdByFoundationCell,
|
|
Func<Vector3Int, bool> isFoundationCell,
|
|
Func<int, bool> 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;
|
|
}
|
|
|
|
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);
|
|
screenPosition = BuildScreenPosition(Input.mousePosition);
|
|
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);
|
|
}
|
|
}
|
|
}
|