refactor(enemy): Boss 选招与战利品掉落改用 WeightedPick;删除零调用的 SelectWeightedSkill 死代码

This commit is contained in:
2026-07-27 09:58:40 +08:00
parent 67220b4bbd
commit 1d5214beea
3 changed files with 22 additions and 69 deletions
+10 -18
View File
@@ -39,8 +39,9 @@ namespace BaseGames.Enemies
public int CurrentPhase => _currentPhase; public int CurrentPhase => _currentPhase;
private Coroutine _counterStaggerCoroutine; private Coroutine _counterStaggerCoroutine;
// 缓存加权候选列表,避免 UseBossSkillWeighted() 每次 new List → GC 分配 // 缓存加权候选与其有效权重(两者等长、下标对应),避免 UseBossSkillWeighted() 每次 new List → GC 分配
private readonly List<(BossSkillSO skill, float w)> _weightedCandidates = new(8); private readonly List<BossSkillSO> _weightedCandidates = new(8);
private readonly List<float> _candidateWeights = new(8);
// 单元素缓冲数组,供 ApplyCounterResponse 缓存当前技能,避免 new[] 分配 // 单元素缓冲数组,供 ApplyCounterResponse 缓存当前技能,避免 new[] 分配
private readonly BossSkillSO[] _singleSkillBuf = new BossSkillSO[1]; private readonly BossSkillSO[] _singleSkillBuf = new BossSkillSO[1];
@@ -110,31 +111,22 @@ namespace BaseGames.Enemies
// 筛选:在当前阶段可用 + 冷却就绪 + weight > 0 // 筛选:在当前阶段可用 + 冷却就绪 + weight > 0
_weightedCandidates.Clear(); _weightedCandidates.Clear();
float totalWeight = 0f; _candidateWeights.Clear();
foreach (var s in skills) foreach (var s in skills)
{ {
if (s == null || s.weight <= 0f) continue; if (s == null || s.weight <= 0f) continue;
if (!_skillExecutor.CanUseSkill(s.skillId)) continue; if (!_skillExecutor.CanUseSkill(s.skillId)) continue;
if (!IsSkillAvailableInPhase(s)) continue; if (!IsSkillAvailableInPhase(s)) continue;
_weightedCandidates.Add(s);
// 防重复:上一个技能权重打折 // 防重复:上一个技能权重打折
float w = s.skillId == LastUsedSkillId ? s.weight * 0.3f : s.weight; _candidateWeights.Add(s.skillId == LastUsedSkillId ? s.weight * 0.3f : s.weight);
_weightedCandidates.Add((s, w));
totalWeight += w;
} }
if (_weightedCandidates.Count == 0 || totalWeight <= 0f) return false; // 加权随机抽取(共享原语:无正权重/无候选时返回 -1)
int idx = BaseGames.Core.WeightedPick.Index(_candidateWeights);
// 加权随机抽取 if (idx < 0) return false;
float roll = UnityEngine.Random.Range(0f, totalWeight); BossSkillSO selected = _weightedCandidates[idx];
BossSkillSO selected = null;
float accum = 0f;
foreach (var (skill, w) in _weightedCandidates)
{
accum += w;
if (roll <= accum) { selected = skill; break; }
}
selected ??= _weightedCandidates[_weightedCandidates.Count - 1].skill;
if (!CheckResourceCost(selected)) return false; if (!CheckResourceCost(selected)) return false;
@@ -127,37 +127,6 @@ namespace BaseGames.Boss
/// <summary>Inspector 中注册的全部技能 SO(只读)。</summary> /// <summary>Inspector 中注册的全部技能 SO(只读)。</summary>
public BossSkillSO[] Skills => _skills; public BossSkillSO[] Skills => _skills;
/// <summary>
/// 从候选技能列表中按 weight 加权随机选择一个技能。
/// 权重为 0 的技能不参与选择;所有候选权重均为 0 时返回 null。
/// </summary>
public BossSkillSO SelectWeightedSkill(System.Collections.Generic.IList<BossSkillSO> candidates)
{
if (candidates == null || candidates.Count == 0) return null;
float totalWeight = 0f;
for (int i = 0; i < candidates.Count; i++)
{
var s = candidates[i];
if (s != null && s.weight > 0f) totalWeight += s.weight;
}
if (totalWeight <= 0f) return null;
float roll = UnityEngine.Random.value * totalWeight;
float acc = 0f;
for (int i = 0; i < candidates.Count; i++)
{
var s = candidates[i];
if (s == null || s.weight <= 0f) continue;
acc += s.weight;
if (roll <= acc) return s;
}
// 浮点精度兜底:返回最后一个有效候选
for (int i = candidates.Count - 1; i >= 0; i--)
if (candidates[i]?.weight > 0f) return candidates[i];
return null;
}
/// <summary> /// <summary>
/// 执行一个 Boss 技能。若当前正在执行或技能冷却未就绪则返回。 /// 执行一个 Boss 技能。若当前正在执行或技能冷却未就绪则返回。
/// </summary> /// </summary>
+12 -20
View File
@@ -33,32 +33,24 @@ namespace BaseGames.Enemies
bool isHard = dm != null && bool isHard = dm != null &&
(int)dm.CurrentLevel >= (int)DifficultyLevel.Hard; (int)dm.CurrentLevel >= (int)DifficultyLevel.Hard;
float totalWeight = 0f; // 有效权重只算一遍(难度加成),再交由共享原语加权抽取;无正权重时不掉落。
foreach (var entry in table.Entries) var weights = new float[table.Entries.Length];
for (int i = 0; i < table.Entries.Length; i++)
{ {
var entry = table.Entries[i];
float w = entry.BaseWeight; float w = entry.BaseWeight;
if (isHard && entry.ScaleWithDifficulty) w *= 1.5f; if (isHard && entry.ScaleWithDifficulty) w *= 1.5f;
totalWeight += w; weights[i] = w;
} }
if (totalWeight <= 0f) return; int idx = WeightedPick.Index(weights);
if (idx < 0) return;
float roll = Random.Range(0f, totalWeight); var picked = table.Entries[idx];
float accum = 0f; if (!string.IsNullOrEmpty(picked.ItemId))
foreach (var entry in table.Entries) CollectibleSpawner.SpawnItem(worldPosition, picked.ItemId);
{ else if (picked.LingZhuAmount > 0)
float w = entry.BaseWeight; CollectibleSpawner.SpawnLingZhu(worldPosition, picked.LingZhuAmount);
if (isHard && entry.ScaleWithDifficulty) w *= 1.5f;
accum += w;
if (roll <= accum)
{
if (!string.IsNullOrEmpty(entry.ItemId))
CollectibleSpawner.SpawnItem(worldPosition, entry.ItemId);
else if (entry.LingZhuAmount > 0)
CollectibleSpawner.SpawnLingZhu(worldPosition, entry.LingZhuAmount);
return;
}
}
} }
private static void ApplyDifficultyLingZhuScale(ref int lingZhu) private static void ApplyDifficultyLingZhuScale(ref int lingZhu)