refactor 1: 新增/重命名类定义
- 将资源服务类型从 CombatResourceManager 重命名为 CombatInRunResourceManager,并同步更新现有引用。
- CombatScheduler.cs:28
- CombatInRunResourceManager.cs:11
- CombatFinishFormState.cs:22
- 新增掉落解析骨架:
- EnemyDropResolveContext.cs:6
- EnemyDropResolveResult.cs:3
- EnemyDropResolver.cs:7
- 新增 phase end condition 骨架:
- IPhaseEndCondition.cs:5
- PhaseEndConditionContext.cs:5
- PhaseEndConditionFactory.cs:5
- 以及 4 个实现类:
- NonePhaseEndCondition
- TimeElapsedPhaseEndCondition
- EnemiesClearedPhaseEndCondition
- BossDeadPhaseEndCondition
This commit is contained in:
parent
0ff04f02f4
commit
1d7c5b80d9
|
|
@ -8,7 +8,7 @@ using Random = UnityEngine.Random;
|
|||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class CombatResourceManager
|
||||
internal sealed class CombatInRunResourceManager
|
||||
{
|
||||
// 每次击杀敌人后,进入“掉组件判定”的概率:
|
||||
// chance = clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0, DropChanceCap)
|
||||
|
|
@ -25,7 +25,7 @@ namespace GeometryTD.CustomComponent
|
|||
private readonly PhaseLoopRuntime _phaseLoopRuntime = new();
|
||||
private readonly CombatLoadSession _loadSession = new();
|
||||
private readonly CombatEventBridge _eventBridge = new();
|
||||
private readonly CombatResourceManager _combatResourceManager = new();
|
||||
private readonly CombatInRunResourceManager _combatInRunResourceManager = new();
|
||||
|
||||
private EntityComponent _entity;
|
||||
private DRLevel _currentLevel;
|
||||
|
|
@ -49,8 +49,8 @@ namespace GeometryTD.CustomComponent
|
|||
public int PhaseCount => _phaseLoopRuntime.PhaseCount;
|
||||
public bool CanEndCombat => _phaseLoopRuntime.CanEndCombat;
|
||||
public int DefeatedEnemyCount => _enemyManager.DefeatedEnemyCount;
|
||||
public int GainedCoin => _combatResourceManager.GainedCoin;
|
||||
public int GainedGold => _combatResourceManager.GainedGold;
|
||||
public int GainedCoin => _combatInRunResourceManager.GainedCoin;
|
||||
public int GainedGold => _combatInRunResourceManager.GainedGold;
|
||||
|
||||
public void OnInit()
|
||||
{
|
||||
|
|
@ -95,7 +95,7 @@ namespace GeometryTD.CustomComponent
|
|||
_enemyManager.EndPhase();
|
||||
_enemyManager.ResetCombatStats();
|
||||
ResetRuntime();
|
||||
_combatResourceManager.Reset();
|
||||
_combatInRunResourceManager.Reset();
|
||||
_isFinishAsVictory = true;
|
||||
|
||||
_currentLevel = level;
|
||||
|
|
@ -192,14 +192,14 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
public void OnEnemyDefeatedRewardResolved(int gainedCoin, int gainedGold)
|
||||
{
|
||||
_combatResourceManager.AddEnemyDefeatedReward(gainedCoin, gainedGold);
|
||||
_combatInRunResourceManager.AddEnemyDefeatedReward(gainedCoin, gainedGold);
|
||||
|
||||
if (!IsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_combatResourceManager.TryRollOutGameItemDrop(
|
||||
_combatInRunResourceManager.TryRollOutGameItemDrop(
|
||||
_phaseLoopRuntime.DisplayPhaseIndex,
|
||||
ResolveCurrentThemeType());
|
||||
}
|
||||
|
|
@ -222,7 +222,7 @@ namespace GeometryTD.CustomComponent
|
|||
_spawnEntriesByPhaseId.Clear();
|
||||
_phaseLoopRuntime.Reset();
|
||||
_loadSession.Reset();
|
||||
_combatResourceManager.Reset();
|
||||
_combatInRunResourceManager.Reset();
|
||||
_settlementContext = null;
|
||||
_currentLevel = null;
|
||||
_isFinishAsVictory = true;
|
||||
|
|
@ -337,8 +337,8 @@ namespace GeometryTD.CustomComponent
|
|||
SettlementContext settlementContext = new SettlementContext
|
||||
{
|
||||
DefeatedEnemyCount = Mathf.Max(0, defeatedEnemyCount),
|
||||
GainedGold = Mathf.Max(0, _combatResourceManager.GainedGold),
|
||||
RewardInventory = _combatResourceManager.GetRewardInventorySnapshot(),
|
||||
GainedGold = Mathf.Max(0, _combatInRunResourceManager.GainedGold),
|
||||
RewardInventory = _combatInRunResourceManager.GetRewardInventorySnapshot(),
|
||||
ShouldOpenRewardSelection = shouldOpenFullBaseHpRewardSelect,
|
||||
Reason = reason
|
||||
};
|
||||
|
|
@ -397,10 +397,10 @@ namespace GeometryTD.CustomComponent
|
|||
}
|
||||
}
|
||||
|
||||
int goldForBonusCalculation = Mathf.Max(0, _combatResourceManager.GainedGold) + levelRewardGold;
|
||||
int goldForBonusCalculation = Mathf.Max(0, _combatInRunResourceManager.GainedGold) + levelRewardGold;
|
||||
int bonusGold = bonusRate > 0f ? Mathf.FloorToInt(goldForBonusCalculation * bonusRate) : 0;
|
||||
int settlementGold = levelRewardGold + bonusGold;
|
||||
_combatResourceManager.AddSettlementGold(settlementGold);
|
||||
_combatInRunResourceManager.AddSettlementGold(settlementGold);
|
||||
|
||||
Log.Info(
|
||||
"Combat settlement resolved. BaseHp={0}/{1}, LevelReward={2}, BonusRate={3:P0}, BonusGold={4}, FullHpRewardSelect={5}, LowHpPenalty={6}.",
|
||||
|
|
@ -437,7 +437,7 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
private bool TryPrepareRewardSelection(SettlementContext settlementContext)
|
||||
{
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = _combatResourceManager.RollSettlementRewardCandidates(
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = _combatInRunResourceManager.RollSettlementRewardCandidates(
|
||||
_phaseLoopRuntime.DisplayPhaseIndex,
|
||||
ResolveCurrentThemeType(),
|
||||
RewardSelectDisplayCount);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal readonly struct EnemyDropResolveContext
|
||||
{
|
||||
public EnemyDropResolveContext(DREnemy enemy, int displayPhaseIndex, LevelThemeType themeType)
|
||||
{
|
||||
Enemy = enemy;
|
||||
DisplayPhaseIndex = displayPhaseIndex;
|
||||
ThemeType = themeType;
|
||||
}
|
||||
|
||||
public DREnemy Enemy { get; }
|
||||
|
||||
public int DisplayPhaseIndex { get; }
|
||||
|
||||
public LevelThemeType ThemeType { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc1fe871193e2594189cac3af541f354
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal readonly struct EnemyDropResolveResult
|
||||
{
|
||||
public static EnemyDropResolveResult Empty => new(0, 0, false);
|
||||
|
||||
public EnemyDropResolveResult(int coin, int gold, bool shouldRollOutGameItem)
|
||||
{
|
||||
Coin = coin;
|
||||
Gold = gold;
|
||||
ShouldRollOutGameItem = shouldRollOutGameItem;
|
||||
}
|
||||
|
||||
public int Coin { get; }
|
||||
|
||||
public int Gold { get; }
|
||||
|
||||
public bool ShouldRollOutGameItem { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 754c09edf691f354aa918c4a730a9cc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using GeometryTD.DataTable;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class EnemyDropResolver
|
||||
{
|
||||
public EnemyDropResolveResult Resolve(in EnemyDropResolveContext context)
|
||||
{
|
||||
DREnemy enemy = context.Enemy;
|
||||
if (enemy == null)
|
||||
{
|
||||
return EnemyDropResolveResult.Empty;
|
||||
}
|
||||
|
||||
int coin = Mathf.Max(0, enemy.DropCoin);
|
||||
int gold = 0;
|
||||
|
||||
float dropRate = enemy.DropPercent > 1f
|
||||
? Mathf.Clamp01(enemy.DropPercent * 0.01f)
|
||||
: Mathf.Clamp01(enemy.DropPercent);
|
||||
|
||||
if (enemy.DropGold > 0 && dropRate > 0f && Random.value <= dropRate)
|
||||
{
|
||||
gold = Mathf.Max(0, enemy.DropGold);
|
||||
}
|
||||
|
||||
return new EnemyDropResolveResult(coin, gold, shouldRollOutGameItem: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7dc48b97505d0242bf5846ba835f3b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9e3f30abcd9a85642b7fe0e9a73254ce
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class BossDeadPhaseEndCondition : IPhaseEndCondition
|
||||
{
|
||||
public PhaseEndType EndType => PhaseEndType.BossDead;
|
||||
|
||||
public bool ShouldExit(in PhaseEndConditionContext context)
|
||||
{
|
||||
return context.IsPhaseSpawnCompleted && !context.HasAliveBoss;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69d0ce2f2c3ee424985fa9775c6291d1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class EnemiesClearedPhaseEndCondition : IPhaseEndCondition
|
||||
{
|
||||
public PhaseEndType EndType => PhaseEndType.EnemiesCleared;
|
||||
|
||||
public bool ShouldExit(in PhaseEndConditionContext context)
|
||||
{
|
||||
return context.IsPhaseSpawnCompleted && context.AliveEnemyCount <= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9a9d79f496dab39479265367593921f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal interface IPhaseEndCondition
|
||||
{
|
||||
PhaseEndType EndType { get; }
|
||||
|
||||
bool ShouldExit(in PhaseEndConditionContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15e7750c40dbb6449bc1bc93370734cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class NonePhaseEndCondition : IPhaseEndCondition
|
||||
{
|
||||
public PhaseEndType EndType => PhaseEndType.None;
|
||||
|
||||
public bool ShouldExit(in PhaseEndConditionContext context)
|
||||
{
|
||||
if (context.Phase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Phase.DurationSeconds > 0 &&
|
||||
context.PhaseElapsedSeconds >= context.Phase.DurationSeconds)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return context.IsPhaseSpawnCompleted && context.AliveEnemyCount <= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27a6e6b0635d41d4d8ba336e05927bab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using GeometryTD.DataTable;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal readonly struct PhaseEndConditionContext
|
||||
{
|
||||
public PhaseEndConditionContext(
|
||||
DRLevelPhase phase,
|
||||
float phaseElapsedSeconds,
|
||||
bool isPhaseSpawnCompleted,
|
||||
int aliveEnemyCount,
|
||||
bool hasAliveBoss)
|
||||
{
|
||||
Phase = phase;
|
||||
PhaseElapsedSeconds = phaseElapsedSeconds;
|
||||
IsPhaseSpawnCompleted = isPhaseSpawnCompleted;
|
||||
AliveEnemyCount = aliveEnemyCount;
|
||||
HasAliveBoss = hasAliveBoss;
|
||||
}
|
||||
|
||||
public DRLevelPhase Phase { get; }
|
||||
|
||||
public float PhaseElapsedSeconds { get; }
|
||||
|
||||
public bool IsPhaseSpawnCompleted { get; }
|
||||
|
||||
public int AliveEnemyCount { get; }
|
||||
|
||||
public bool HasAliveBoss { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d4ce36bacd2ae574dbd77a9441cbbecb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal static class PhaseEndConditionFactory
|
||||
{
|
||||
private static readonly IPhaseEndCondition None = new NonePhaseEndCondition();
|
||||
private static readonly IPhaseEndCondition TimeElapsed = new TimeElapsedPhaseEndCondition();
|
||||
private static readonly IPhaseEndCondition EnemiesCleared = new EnemiesClearedPhaseEndCondition();
|
||||
private static readonly IPhaseEndCondition BossDead = new BossDeadPhaseEndCondition();
|
||||
|
||||
public static IPhaseEndCondition Create(PhaseEndType endType)
|
||||
{
|
||||
return endType switch
|
||||
{
|
||||
PhaseEndType.TimeElapsed => TimeElapsed,
|
||||
PhaseEndType.EnemiesCleared => EnemiesCleared,
|
||||
PhaseEndType.BossDead => BossDead,
|
||||
PhaseEndType.None => None,
|
||||
_ => None
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 35a7aac328337414dbae929053176177
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using System.Globalization;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal sealed class TimeElapsedPhaseEndCondition : IPhaseEndCondition
|
||||
{
|
||||
public PhaseEndType EndType => PhaseEndType.TimeElapsed;
|
||||
|
||||
public bool ShouldExit(in PhaseEndConditionContext context)
|
||||
{
|
||||
if (context.Phase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return context.PhaseElapsedSeconds >= ResolveTimeElapsedThreshold(context.Phase);
|
||||
}
|
||||
|
||||
private static float ResolveTimeElapsedThreshold(DRLevelPhase phase)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(phase.EndParam) &&
|
||||
float.TryParse(phase.EndParam, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
|
||||
if (phase.DurationSeconds > 0)
|
||||
{
|
||||
return phase.DurationSeconds;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 39315af578eed09408c2a088fb83d409
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -19,7 +19,7 @@ namespace GeometryTD.CustomComponent
|
|||
}
|
||||
|
||||
Scheduler.CommitSettlementInventory(Scheduler._settlementContext);
|
||||
Scheduler._settlementContext.GainedGold = Mathf.Max(0, Scheduler._combatResourceManager.GainedGold);
|
||||
Scheduler._settlementContext.GainedGold = Mathf.Max(0, Scheduler._combatInRunResourceManager.GainedGold);
|
||||
Scheduler.OpenCombatFinishForm(Scheduler._settlementContext);
|
||||
Scheduler.ChangeState(new CombatWaitingForReturnState(Scheduler));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue