Update CombatNodeArchitecture.md
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomUtility;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.Entity
|
||||
{
|
||||
public sealed class CombatSelectUseCaseConfigurator
|
||||
{
|
||||
private const int BuildOptionCount = 4;
|
||||
|
||||
private readonly BuildTowerVisualInfo[] _buildTowerVisualInfos = new BuildTowerVisualInfo[BuildOptionCount];
|
||||
|
||||
public void Configure(
|
||||
CombatSelectFormUseCase useCase,
|
||||
Func<int> coinProvider,
|
||||
Func<int, Func<bool>> buildActionFactory,
|
||||
Func<bool> upgradeAction,
|
||||
int upgradeCost,
|
||||
Func<bool> destroyAction,
|
||||
int destroyGain,
|
||||
int[] buildTowerCosts,
|
||||
int currentBuildTowerCount,
|
||||
BackpackInventoryData inventorySnapshot,
|
||||
IReadOnlyList<TowerItemData> participantTowers)
|
||||
{
|
||||
if (useCase == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
useCase.SetCoinProvider(coinProvider);
|
||||
|
||||
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(inventorySnapshot?.MuzzleComponents);
|
||||
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(inventorySnapshot?.BearingComponents);
|
||||
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(inventorySnapshot?.BaseComponents);
|
||||
|
||||
int availableBuildCount = Mathf.Clamp(currentBuildTowerCount, 0, BuildOptionCount);
|
||||
for (int i = 0; i < BuildOptionCount; i++)
|
||||
{
|
||||
bool isBuildAvailable = i < availableBuildCount;
|
||||
BuildTowerVisualInfo buildVisual = ResolveBuildTowerVisual(participantTowers, i, muzzleMap, bearingMap, baseMap);
|
||||
_buildTowerVisualInfos[i] = buildVisual;
|
||||
useCase.SetBuildAction(
|
||||
i,
|
||||
isBuildAvailable && buildActionFactory != null ? buildActionFactory.Invoke(i) : null,
|
||||
GetBuildTowerCost(buildTowerCosts, i),
|
||||
null,
|
||||
isBuildAvailable,
|
||||
buildVisual.BaseColor,
|
||||
buildVisual.BearingColor,
|
||||
buildVisual.MuzzleColor);
|
||||
useCase.SetBuildVisible(i, isBuildAvailable);
|
||||
}
|
||||
|
||||
useCase.SetUpgradeAction(upgradeAction, Mathf.Max(0, upgradeCost));
|
||||
useCase.SetDestroyAction(destroyAction, Mathf.Max(0, destroyGain));
|
||||
}
|
||||
|
||||
public BuildTowerVisualInfo GetBuildVisualInfo(int buildIndex)
|
||||
{
|
||||
if (buildIndex < 0 || buildIndex >= _buildTowerVisualInfos.Length)
|
||||
{
|
||||
return BuildTowerVisualInfo.Default;
|
||||
}
|
||||
|
||||
return _buildTowerVisualInfos[buildIndex];
|
||||
}
|
||||
|
||||
private static int GetBuildTowerCost(int[] buildTowerCosts, int buildIndex)
|
||||
{
|
||||
if (buildTowerCosts == null || buildIndex < 0 || buildIndex >= buildTowerCosts.Length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Max(0, buildTowerCosts[buildIndex]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public 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; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomComponent;
|
||||
using GeometryTD.CustomUtility;
|
||||
using GeometryTD.Map;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Entity.EntityData;
|
||||
@@ -37,7 +36,7 @@ namespace GeometryTD.Entity
|
||||
private TowerPlacementService _towerPlacementService;
|
||||
private TowerSelectionPresenter _towerSelectionPresenter;
|
||||
|
||||
private readonly BuildTowerVisualInfo[] _buildTowerVisualInfos = new BuildTowerVisualInfo[4];
|
||||
private CombatSelectUseCaseConfigurator _combatSelectUseCaseConfigurator;
|
||||
|
||||
public IReadOnlyList<Vector3Int> PathCells => _mapTopologyService != null
|
||||
? _mapTopologyService.PathCells
|
||||
@@ -102,6 +101,7 @@ namespace GeometryTD.Entity
|
||||
}
|
||||
|
||||
InitializeCombatSelectUseCase();
|
||||
InitializeCombatSelectUseCaseConfigurator();
|
||||
InitializeCombatSelectInputService();
|
||||
InitializeMapTopologyService();
|
||||
InitializeTowerPlacementService();
|
||||
@@ -127,7 +127,9 @@ namespace GeometryTD.Entity
|
||||
{
|
||||
HideCombatSelectForm();
|
||||
_towerPlacementService?.HideAndClearAllPlacedTowers();
|
||||
ClearRuntimeData();
|
||||
ClearSelectionState();
|
||||
ClearTowerTracking();
|
||||
ClearMapTopology();
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
|
||||
@@ -139,7 +141,9 @@ namespace GeometryTD.Entity
|
||||
|
||||
private void RefreshTiles()
|
||||
{
|
||||
ClearRuntimeData();
|
||||
ClearMapTopology();
|
||||
ClearTowerTracking();
|
||||
ClearSelectionState();
|
||||
|
||||
if (_mapDataRefs == null)
|
||||
{
|
||||
@@ -161,10 +165,18 @@ namespace GeometryTD.Entity
|
||||
_mapTopologyService?.Refresh(tilemap, Spawners, House, name, _mapData != null ? _mapData.LevelId : 0);
|
||||
}
|
||||
|
||||
private void ClearRuntimeData()
|
||||
private void ClearMapTopology()
|
||||
{
|
||||
_mapTopologyService?.Clear();
|
||||
}
|
||||
|
||||
private void ClearTowerTracking()
|
||||
{
|
||||
_towerPlacementService?.ClearTracking();
|
||||
}
|
||||
|
||||
private void ClearSelectionState()
|
||||
{
|
||||
_towerSelectionPresenter?.ClearSelectedObject();
|
||||
}
|
||||
|
||||
@@ -178,6 +190,14 @@ namespace GeometryTD.Entity
|
||||
GameEntry.UIRouter.BindUIUseCase(UIFormType.CombatSelectForm, _combatSelectFormUseCase);
|
||||
}
|
||||
|
||||
private void InitializeCombatSelectUseCaseConfigurator()
|
||||
{
|
||||
if (_combatSelectUseCaseConfigurator == null)
|
||||
{
|
||||
_combatSelectUseCaseConfigurator = new CombatSelectUseCaseConfigurator();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeTowerSelectionPresenter()
|
||||
{
|
||||
if (_towerSelectionPresenter == null)
|
||||
@@ -212,11 +232,6 @@ namespace GeometryTD.Entity
|
||||
|
||||
private void ConfigureCombatSelectUseCase()
|
||||
{
|
||||
if (_combatSelectFormUseCase == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_combatSelectFormUseCase.SetCoinProvider(GetCurrentCoin);
|
||||
BackpackInventoryData inventorySnapshot = GameEntry.PlayerInventory != null
|
||||
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
||||
@@ -224,32 +239,18 @@ namespace GeometryTD.Entity
|
||||
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,
|
||||
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));
|
||||
_combatSelectUseCaseConfigurator?.Configure(
|
||||
_combatSelectFormUseCase,
|
||||
GetCurrentCoin,
|
||||
buildIndex => () => TryBuildTower(buildIndex),
|
||||
TryUpgradeTower,
|
||||
_upgradeCost,
|
||||
TryDestroyTower,
|
||||
_destroyGain,
|
||||
_buildTowerCosts,
|
||||
GetCurrentBuildTowerCount(),
|
||||
inventorySnapshot,
|
||||
participantTowers);
|
||||
}
|
||||
|
||||
private void HandleCombatSelectInput()
|
||||
@@ -306,8 +307,8 @@ namespace GeometryTD.Entity
|
||||
return false;
|
||||
}
|
||||
|
||||
BuildTowerVisualInfo buildVisual = buildIndex >= 0 && buildIndex < _buildTowerVisualInfos.Length
|
||||
? _buildTowerVisualInfos[buildIndex]
|
||||
BuildTowerVisualInfo buildVisual = _combatSelectUseCaseConfigurator != null
|
||||
? _combatSelectUseCaseConfigurator.GetBuildVisualInfo(buildIndex)
|
||||
: BuildTowerVisualInfo.Default;
|
||||
|
||||
if (!_towerPlacementService.TryBuildTower(selectedFoundationCell, IsFoundationCell, buildIndex, _buildTowerCosts,
|
||||
@@ -375,16 +376,6 @@ namespace GeometryTD.Entity
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.CombatSelectForm);
|
||||
}
|
||||
|
||||
private int GetBuildTowerCost(int buildIndex)
|
||||
{
|
||||
if (_buildTowerCosts == null || buildIndex < 0 || buildIndex >= _buildTowerCosts.Length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Max(0, _buildTowerCosts[buildIndex]);
|
||||
}
|
||||
|
||||
private static int GetCurrentBuildTowerCount()
|
||||
{
|
||||
if (GameEntry.CombatNode == null)
|
||||
@@ -395,67 +386,6 @@ namespace GeometryTD.Entity
|
||||
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);
|
||||
@@ -477,22 +407,6 @@ 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);
|
||||
|
||||
Reference in New Issue
Block a user