refactor 4:

- CombatWaitingForPhaseEndState.cs 不再调用旧的 PhaseLoopRuntime.ShouldEndCurrentPhase(...),改为构造 PhaseEndConditionContext,再通过
PhaseEndConditionFactory.Create(currentPhase.EndType) 执行判定。
- PhaseLoopRuntime.cs 删除了旧的 phase 结束规则实现,现在只保留 phase 运行时数据管理,职责和架构文档一致。
- 为了让 BossDeadPhaseEndCondition 真正可用,我补了 boss 真值链路:
    - EnemyLifecycleTracker.cs 现在会跟踪存活 boss。
    - EnemyManager.cs 暴露 HasAliveBoss,并在 EntryType.Boss 刷怪时标记 boss 身份。
This commit is contained in:
2026-03-07 14:45:42 +08:00
parent 91eeeaaeea
commit e488a2ca0f
4 changed files with 31 additions and 51 deletions
@@ -6,22 +6,28 @@ namespace GeometryTD.CustomComponent
{
internal sealed class EnemyLifecycleTracker
{
private readonly HashSet<int> _aliveBossEntityIds = new();
private readonly HashSet<int> _trackedEnemyEntityIds = new();
private readonly Dictionary<int, DREnemy> _trackedEnemyConfigByEntityId = new();
private readonly Dictionary<int, bool> _bossFlagsByEntityId = new();
public int AliveEnemyCount { get; private set; }
public bool HasAliveBoss => _aliveBossEntityIds.Count > 0;
public void Reset()
{
_aliveBossEntityIds.Clear();
_bossFlagsByEntityId.Clear();
_trackedEnemyEntityIds.Clear();
_trackedEnemyConfigByEntityId.Clear();
AliveEnemyCount = 0;
}
public void TrackEnemy(int entityId, DREnemy enemyConfig)
public void TrackEnemy(int entityId, DREnemy enemyConfig, bool isBoss)
{
_trackedEnemyEntityIds.Add(entityId);
_trackedEnemyConfigByEntityId[entityId] = enemyConfig;
_bossFlagsByEntityId[entityId] = isBoss;
}
public bool Contains(int entityId)
@@ -34,11 +40,17 @@ namespace GeometryTD.CustomComponent
if (_trackedEnemyEntityIds.Contains(entityId))
{
AliveEnemyCount++;
if (_bossFlagsByEntityId.TryGetValue(entityId, out bool isBoss) && isBoss)
{
_aliveBossEntityIds.Add(entityId);
}
}
}
public void HandleShowFailure(int entityId)
{
_aliveBossEntityIds.Remove(entityId);
_bossFlagsByEntityId.Remove(entityId);
_trackedEnemyEntityIds.Remove(entityId);
_trackedEnemyConfigByEntityId.Remove(entityId);
}
@@ -48,11 +60,15 @@ namespace GeometryTD.CustomComponent
enemyConfig = null;
if (!_trackedEnemyEntityIds.Remove(entityId))
{
_aliveBossEntityIds.Remove(entityId);
_bossFlagsByEntityId.Remove(entityId);
_trackedEnemyConfigByEntityId.Remove(entityId);
return false;
}
_trackedEnemyConfigByEntityId.TryGetValue(entityId, out enemyConfig);
_aliveBossEntityIds.Remove(entityId);
_bossFlagsByEntityId.Remove(entityId);
_trackedEnemyConfigByEntityId.Remove(entityId);
AliveEnemyCount = Mathf.Max(0, AliveEnemyCount - 1);
return true;
@@ -24,6 +24,7 @@ namespace GeometryTD.CustomComponent
public int AliveEnemyCount => _enemyLifecycleTracker.AliveEnemyCount;
public int DefeatedEnemyCount => _defeatedEnemyCount;
public bool HasAliveBoss => _enemyLifecycleTracker.HasAliveBoss;
public bool IsPhaseSpawnCompleted => _enemySpawnDirector.IsPhaseSpawnCompleted;
public bool IsPhaseRunning => _enemySpawnDirector.IsPhaseRunning;
@@ -150,11 +151,12 @@ namespace GeometryTD.CustomComponent
}
int scaledBaseHp = _enemyConfigService.ResolveScaledEnemyBaseHp(enemyConfig.BaseHp, _combatScheduler);
bool isBoss = entry.EntryType == Definition.EntryType.Boss;
for (int i = 0; i < spawnCount; i++)
{
int enemyEntityId = _entity.GenerateSerialId();
_enemyLifecycleTracker.TrackEnemy(enemyEntityId, enemyConfig);
_enemyLifecycleTracker.TrackEnemy(enemyEntityId, enemyConfig, isBoss);
EnemyData enemyData = new EnemyData(
enemyEntityId,
enemyConfig.EntityId,