补充参战防御塔进入战斗逻辑

- 将 Inventory 中参战的防御塔数据传递到 CombatSelectForm 中
- 为防御塔的图标展示添加 TowerRepoItem 与 TowerIconArea 适配防御塔的三层 Image
This commit is contained in:
SepComet
2026-03-05 13:44:49 +08:00
parent 9db9aeabcd
commit 8a478982f8
56 changed files with 2507 additions and 467 deletions
@@ -9,15 +9,22 @@ namespace GeometryTD.Entity.EntityData
{
[SerializeField] private TowerStatsData _stats = new TowerStatsData();
[SerializeField] private int _towerLevel = 0;
[SerializeField] private Color _muzzleColor = Color.white;
[SerializeField] private Color _bearingColor = Color.white;
[SerializeField] private Color _baseColor = Color.white;
public TowerData(int entityId, int typeId, Vector3 position, Quaternion rotation,
TowerStatsData stats, int towerLevel = 0)
TowerStatsData stats, int towerLevel = 0, Color? muzzleColor = null, Color? bearingColor = null,
Color? baseColor = null)
: base(entityId, typeId)
{
Position = position;
Rotation = rotation;
_stats = stats ?? new TowerStatsData();
_towerLevel = Mathf.Max(0, towerLevel);
_muzzleColor = muzzleColor ?? Color.white;
_bearingColor = bearingColor ?? Color.white;
_baseColor = baseColor ?? Color.white;
}
public TowerStatsData Stats
@@ -31,5 +38,23 @@ namespace GeometryTD.Entity.EntityData
get => _towerLevel;
set => _towerLevel = Mathf.Max(0, value);
}
public Color MuzzleColor
{
get => _muzzleColor;
set => _muzzleColor = value;
}
public Color BearingColor
{
get => _bearingColor;
set => _bearingColor = value;
}
public Color BaseColor
{
get => _baseColor;
set => _baseColor = value;
}
}
}
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using GeometryTD.CustomComponent;
using GeometryTD.CustomUtility;
using GeometryTD.Map;
using GeometryTD.Definition;
using GeometryTD.Entity.EntityData;
@@ -14,12 +16,17 @@ namespace GeometryTD.Entity
public class MapEntity : EntityBase
{
private const int DefaultTowerTypeId = 401;
private static readonly Spawner[] EmptySpawners = Array.Empty<Spawner>();
[SerializeField] private bool _enableCombatSelectInput = true;
[SerializeField] private int _towerTypeId = DefaultTowerTypeId;
[SerializeField] private int[] _buildTowerCosts = { 40, 60, 60, 80 };
[SerializeField] private int _upgradeCost = 50;
[SerializeField] private int _destroyGain = 40;
private MapDataRefs _mapDataRefs;
@@ -29,6 +36,8 @@ namespace GeometryTD.Entity
private CombatSelectInputService _combatSelectInputService;
private TowerPlacementService _towerPlacementService;
private TowerSelectionPresenter _towerSelectionPresenter;
private readonly BuildTowerVisualInfo[] _buildTowerVisualInfos = new BuildTowerVisualInfo[4];
public IReadOnlyList<Vector3Int> PathCells => _mapTopologyService != null
? _mapTopologyService.PathCells
@@ -209,22 +218,38 @@ namespace GeometryTD.Entity
}
_combatSelectFormUseCase.SetCoinProvider(GetCurrentCoin);
BackpackInventoryData inventorySnapshot = GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: null;
IReadOnlyList<TowerItemData> participantTowers = GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetParticipantTowerSnapshot()
: null;
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(inventorySnapshot?.MuzzleComponents);
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(inventorySnapshot?.BearingComponents);
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(inventorySnapshot?.BaseComponents);
int currentBuildTowerCount = GetCurrentBuildTowerCount();
for (int i = 0; i < 4; i++)
{
int buildIndex = i;
int buildCost = GetBuildTowerCost(buildIndex);
bool isBuildAvailable = buildIndex < currentBuildTowerCount;
BuildTowerVisualInfo buildVisual = ResolveBuildTowerVisual(participantTowers, buildIndex, muzzleMap, bearingMap, baseMap);
_buildTowerVisualInfos[buildIndex] = buildVisual;
_combatSelectFormUseCase.SetBuildAction(
buildIndex,
() => TryBuildTower(buildIndex),
GetBuildTowerCost(buildIndex));
isBuildAvailable ? () => TryBuildTower(buildIndex) : (Func<bool>)null,
buildCost,
null,
isBuildAvailable,
buildVisual.BaseColor,
buildVisual.BearingColor,
buildVisual.MuzzleColor);
_combatSelectFormUseCase.SetBuildVisible(buildIndex, isBuildAvailable);
}
_combatSelectFormUseCase.SetUpgradeAction(
TryUpgradeTower,
Mathf.Max(0, _upgradeCost));
_combatSelectFormUseCase.SetDestroyAction(
TryDestroyTower,
Mathf.Max(0, _destroyGain));
_combatSelectFormUseCase.SetUpgradeAction(TryUpgradeTower, Mathf.Max(0, _upgradeCost));
_combatSelectFormUseCase.SetDestroyAction(TryDestroyTower, Mathf.Max(0, _destroyGain));
}
private void HandleCombatSelectInput()
@@ -275,8 +300,18 @@ namespace GeometryTD.Entity
return false;
}
CombatNodeComponent combatNode = GameEntry.CombatNode;
if (combatNode == null || !combatNode.TryGetBuildTowerStats(buildIndex, out TowerStatsData buildTowerStats))
{
return false;
}
BuildTowerVisualInfo buildVisual = buildIndex >= 0 && buildIndex < _buildTowerVisualInfos.Length
? _buildTowerVisualInfos[buildIndex]
: BuildTowerVisualInfo.Default;
if (!_towerPlacementService.TryBuildTower(selectedFoundationCell, IsFoundationCell, buildIndex, _buildTowerCosts,
_towerTypeId, Tilemap, TryConsumeCoin, AddCoin, out int towerEntityId))
buildTowerStats, buildVisual.MuzzleColor, buildVisual.BearingColor, buildVisual.BaseColor, _towerTypeId, Tilemap, TryConsumeCoin, AddCoin, out int towerEntityId))
{
return false;
}
@@ -350,6 +385,77 @@ namespace GeometryTD.Entity
return Mathf.Max(0, _buildTowerCosts[buildIndex]);
}
private static int GetCurrentBuildTowerCount()
{
if (GameEntry.CombatNode == null)
{
return 0;
}
return Mathf.Clamp(GameEntry.CombatNode.CurrentBuildTowerCount, 0, 4);
}
private static BuildTowerVisualInfo ResolveBuildTowerVisual(
IReadOnlyList<TowerItemData> participantTowers,
int buildIndex,
IReadOnlyDictionary<long, MuzzleCompItemData> muzzleMap,
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
IReadOnlyDictionary<long, BaseCompItemData> baseMap)
{
if (participantTowers == null || buildIndex < 0 || buildIndex >= participantTowers.Count)
{
return BuildTowerVisualInfo.Default;
}
TowerItemData tower = participantTowers[buildIndex];
if (tower == null)
{
return BuildTowerVisualInfo.Default;
}
Color muzzleColor = ResolveComponentColor(muzzleMap, tower.MuzzleComponentInstanceId);
Color bearingColor = ResolveComponentColor(bearingMap, tower.BearingComponentInstanceId);
Color baseColor = ResolveComponentColor(baseMap, tower.BaseComponentInstanceId);
return new BuildTowerVisualInfo(muzzleColor, bearingColor, baseColor);
}
private static Color ResolveComponentColor<TComp>(IReadOnlyDictionary<long, TComp> componentMap, long componentId)
where TComp : TowerCompItemData
{
if (componentMap == null || componentId <= 0)
{
return Color.white;
}
return componentMap.TryGetValue(componentId, out TComp component) && component != null
? IconColorGenerator.GenerateForComponent(component)
: Color.white;
}
private static Dictionary<long, TComp> BuildComponentMap<TComp>(IReadOnlyList<TComp> items)
where TComp : TowerCompItemData
{
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
if (items == null)
{
return map;
}
for (int i = 0; i < items.Count; i++)
{
TComp item = items[i];
if (item == null || item.InstanceId <= 0)
{
continue;
}
map[item.InstanceId] = item;
}
return map;
}
private static bool TryConsumeCoin(int cost)
{
int requiredCoin = Mathf.Max(0, cost);
@@ -371,6 +477,22 @@ namespace GeometryTD.Entity
return GameEntry.CombatNode != null ? Mathf.Max(0, GameEntry.CombatNode.CurrentCoin) : 0;
}
private readonly struct BuildTowerVisualInfo
{
public static BuildTowerVisualInfo Default => new BuildTowerVisualInfo(Color.white, Color.white, Color.white);
public BuildTowerVisualInfo(Color muzzleColor, Color bearingColor, Color baseColor)
{
MuzzleColor = muzzleColor;
BearingColor = bearingColor;
BaseColor = baseColor;
}
public Color MuzzleColor { get; }
public Color BearingColor { get; }
public Color BaseColor { get; }
}
private static void AddCoin(int coin)
{
int amount = Mathf.Max(0, coin);
@@ -382,3 +504,4 @@ namespace GeometryTD.Entity
}
}
}
@@ -53,7 +53,12 @@ namespace GeometryTD.Entity
return;
}
_towerController.OnInit(towerData.Stats, towerData.TowerLevel);
_towerController.OnInit(
towerData.Stats,
towerData.TowerLevel,
towerData.MuzzleColor,
towerData.BearingColor,
towerData.BaseColor);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)