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

- 将 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
@@ -23,6 +23,7 @@ namespace GeometryTD.CustomComponent
private readonly Dictionary<int, List<DRLevelSpawnEntry>> _spawnEntriesByPhaseId = new();
private readonly Dictionary<int, IReadOnlyList<DRLevelSpawnEntry>> _selectedSpawnEntriesByPhaseId = new();
private readonly List<int> _levelIdBuffer = new();
private readonly List<TowerStatsData> _currentBuildTowerStats = new();
private readonly CombatScheduler _combatScheduler = new CombatScheduler();
private bool _runtimeInitialized;
@@ -39,6 +40,7 @@ namespace GeometryTD.CustomComponent
public int CurrentBaseHp => _currentBaseHp;
public bool LastCombatSucceeded => _lastCombatSucceeded;
public bool CanEndCombat => _combatScheduler.CanEndCombat;
public int CurrentBuildTowerCount => _currentBuildTowerStats.Count;
public int LastDefeatedEnemyCount { get; private set; }
public int LastGainedCoin { get; private set; }
public int LastGainedGold { get; private set; }
@@ -88,6 +90,7 @@ namespace GeometryTD.CustomComponent
_spawnEntriesByPhaseId.Clear();
_selectedSpawnEntriesByPhaseId.Clear();
_levelIdBuffer.Clear();
_currentBuildTowerStats.Clear();
IDataTable<DRLevel> dtLevel = GameEntry.DataTable.GetDataTable<DRLevel>();
IDataTable<DRLevelPhase> dtLevelPhase = GameEntry.DataTable.GetDataTable<DRLevelPhase>();
@@ -181,6 +184,7 @@ namespace GeometryTD.CustomComponent
public void StartCombat()
{
_currentBuildTowerStats.Clear();
if (!EnsureCombatRuntimeInitialized())
{
Log.Warning("CombatNodeComponent start failed. Missing scheduler runtime.");
@@ -216,6 +220,7 @@ namespace GeometryTD.CustomComponent
}
CurrentLevel = selectedLevel;
CacheBuildTowerStatsSnapshot();
_isCombatActive = false;
_currentCoin = Mathf.Max(0, selectedLevel.StartCoin);
_currentGold = 0;
@@ -230,6 +235,7 @@ namespace GeometryTD.CustomComponent
_currentCoin = 0;
_currentGold = 0;
_currentBaseHp = 0;
_currentBuildTowerStats.Clear();
return;
}
@@ -252,6 +258,7 @@ namespace GeometryTD.CustomComponent
_currentGold = 0;
_currentBaseHp = 0;
CurrentLevel = null;
_currentBuildTowerStats.Clear();
GameEntry.Event.Fire(this, NodeCompleteEventArgs.Create());
}
@@ -281,6 +288,7 @@ namespace GeometryTD.CustomComponent
LastDefeatedEnemyCount = 0;
LastGainedCoin = 0;
LastGainedGold = 0;
_currentBuildTowerStats.Clear();
ShutdownCombatRuntime();
}
@@ -341,6 +349,18 @@ namespace GeometryTD.CustomComponent
return true;
}
public bool TryGetBuildTowerStats(int buildIndex, out TowerStatsData stats)
{
stats = null;
if (buildIndex < 0 || buildIndex >= _currentBuildTowerStats.Count)
{
return false;
}
stats = CloneTowerStats(_currentBuildTowerStats[buildIndex]);
return stats != null;
}
public void AddCoin(int coin)
{
int gainCoin = Mathf.Max(0, coin);
@@ -353,6 +373,54 @@ namespace GeometryTD.CustomComponent
FireCoinChangedEventIfNeeded();
}
private void CacheBuildTowerStatsSnapshot()
{
_currentBuildTowerStats.Clear();
if (GameEntry.PlayerInventory == null)
{
return;
}
IReadOnlyList<TowerItemData> towers = GameEntry.PlayerInventory.GetParticipantTowerSnapshot();
if (towers == null || towers.Count <= 0)
{
return;
}
for (int i = 0; i < towers.Count; i++)
{
TowerItemData tower = towers[i];
TowerStatsData clonedStats = CloneTowerStats(tower?.Stats);
if (clonedStats == null)
{
continue;
}
_currentBuildTowerStats.Add(clonedStats);
}
}
private static TowerStatsData CloneTowerStats(TowerStatsData source)
{
if (source == null)
{
return null;
}
return new TowerStatsData
{
AttackDamage = source.AttackDamage != null ? (int[])source.AttackDamage.Clone() : null,
DamageRandomRate = source.DamageRandomRate,
RotateSpeed = source.RotateSpeed != null ? (float[])source.RotateSpeed.Clone() : null,
AttackRange = source.AttackRange != null ? (float[])source.AttackRange.Clone() : null,
AttackSpeed = source.AttackSpeed != null ? (float[])source.AttackSpeed.Clone() : null,
AttackMethodType = source.AttackMethodType,
AttackPropertyType = source.AttackPropertyType,
Tags = source.Tags != null ? (TagType[])source.Tags.Clone() : null
};
}
private void OnDestroy()
{
OnShutdown();
@@ -437,3 +505,5 @@ namespace GeometryTD.CustomComponent
}
}
}
@@ -1,4 +1,5 @@
using GeometryTD.CustomUtility;
using System.Collections.Generic;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using UnityGameFramework.Runtime;
@@ -44,6 +45,31 @@ namespace GeometryTD.CustomComponent
return _queryModel.GetSnapshot();
}
public IReadOnlyList<TowerItemData> GetParticipantTowerSnapshot()
{
EnsureInitialized();
BackpackInventoryData inventory = _queryModel.Inventory;
if (inventory?.ParticipantTowerInstanceIds == null || inventory.ParticipantTowerInstanceIds.Count <= 0)
{
return new List<TowerItemData>();
}
List<TowerItemData> result = new List<TowerItemData>(inventory.ParticipantTowerInstanceIds.Count);
for (int i = 0; i < inventory.ParticipantTowerInstanceIds.Count && result.Count < MaxParticipantTowerCount; i++)
{
long towerId = inventory.ParticipantTowerInstanceIds[i];
if (!_queryModel.TryGetTowerById(towerId, out TowerItemData tower) || tower == null)
{
continue;
}
result.Add(InventoryCloneUtility.CloneTower(tower));
}
return result;
}
public void MergeInventory(BackpackInventoryData gainedInventory)
{
EnsureInitialized();
@@ -126,3 +152,4 @@ namespace GeometryTD.CustomComponent
}
}
}