122 lines
4.9 KiB
C#
122 lines
4.9 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 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,
|
|
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 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);
|
|
}
|
|
}
|
|
}
|