From 1d5214beea1769ad022b6c778df1c833448a66d3 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Mon, 27 Jul 2026 09:58:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor(enemy):=20Boss=20=E9=80=89=E6=8B=9B?= =?UTF-8?q?=E4=B8=8E=E6=88=98=E5=88=A9=E5=93=81=E6=8E=89=E8=90=BD=E6=94=B9?= =?UTF-8?q?=E7=94=A8=20WeightedPick;=E5=88=A0=E9=99=A4=E9=9B=B6=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E7=9A=84=20SelectWeightedSkill=20=E6=AD=BB=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/_Game/Scripts/Enemies/Boss/BossBase.cs | 28 ++++++---------- .../Scripts/Enemies/Boss/BossSkillExecutor.cs | 31 ------------------ Assets/_Game/Scripts/Enemies/LootResolver.cs | 32 +++++++------------ 3 files changed, 22 insertions(+), 69 deletions(-) diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossBase.cs b/Assets/_Game/Scripts/Enemies/Boss/BossBase.cs index 27d0d9f9..afbcfc5d 100644 --- a/Assets/_Game/Scripts/Enemies/Boss/BossBase.cs +++ b/Assets/_Game/Scripts/Enemies/Boss/BossBase.cs @@ -39,8 +39,9 @@ namespace BaseGames.Enemies public int CurrentPhase => _currentPhase; private Coroutine _counterStaggerCoroutine; - // 缓存加权候选列表,避免 UseBossSkillWeighted() 每次 new List → GC 分配 - private readonly List<(BossSkillSO skill, float w)> _weightedCandidates = new(8); + // 缓存加权候选与其有效权重(两者等长、下标对应),避免 UseBossSkillWeighted() 每次 new List → GC 分配 + private readonly List _weightedCandidates = new(8); + private readonly List _candidateWeights = new(8); // 单元素缓冲数组,供 ApplyCounterResponse 缓存当前技能,避免 new[] 分配 private readonly BossSkillSO[] _singleSkillBuf = new BossSkillSO[1]; @@ -110,31 +111,22 @@ namespace BaseGames.Enemies // 筛选:在当前阶段可用 + 冷却就绪 + weight > 0 _weightedCandidates.Clear(); - float totalWeight = 0f; + _candidateWeights.Clear(); foreach (var s in skills) { if (s == null || s.weight <= 0f) continue; if (!_skillExecutor.CanUseSkill(s.skillId)) continue; if (!IsSkillAvailableInPhase(s)) continue; + _weightedCandidates.Add(s); // 防重复:上一个技能权重打折 - float w = s.skillId == LastUsedSkillId ? s.weight * 0.3f : s.weight; - _weightedCandidates.Add((s, w)); - totalWeight += w; + _candidateWeights.Add(s.skillId == LastUsedSkillId ? s.weight * 0.3f : s.weight); } - if (_weightedCandidates.Count == 0 || totalWeight <= 0f) return false; - - // 加权随机抽取 - float roll = UnityEngine.Random.Range(0f, totalWeight); - 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; + // 加权随机抽取(共享原语:无正权重/无候选时返回 -1) + int idx = BaseGames.Core.WeightedPick.Index(_candidateWeights); + if (idx < 0) return false; + BossSkillSO selected = _weightedCandidates[idx]; if (!CheckResourceCost(selected)) return false; diff --git a/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs b/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs index 5543ac2c..9be6312a 100644 --- a/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs +++ b/Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs @@ -127,37 +127,6 @@ namespace BaseGames.Boss /// Inspector 中注册的全部技能 SO(只读)。 public BossSkillSO[] Skills => _skills; - /// - /// 从候选技能列表中按 weight 加权随机选择一个技能。 - /// 权重为 0 的技能不参与选择;所有候选权重均为 0 时返回 null。 - /// - public BossSkillSO SelectWeightedSkill(System.Collections.Generic.IList 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; - } - /// /// 执行一个 Boss 技能。若当前正在执行或技能冷却未就绪则返回。 /// diff --git a/Assets/_Game/Scripts/Enemies/LootResolver.cs b/Assets/_Game/Scripts/Enemies/LootResolver.cs index 7f9d986b..f4c1dac6 100644 --- a/Assets/_Game/Scripts/Enemies/LootResolver.cs +++ b/Assets/_Game/Scripts/Enemies/LootResolver.cs @@ -33,32 +33,24 @@ namespace BaseGames.Enemies bool isHard = dm != null && (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; 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); - float accum = 0f; - foreach (var entry in table.Entries) - { - float w = entry.BaseWeight; - 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; - } - } + var picked = table.Entries[idx]; + if (!string.IsNullOrEmpty(picked.ItemId)) + CollectibleSpawner.SpawnItem(worldPosition, picked.ItemId); + else if (picked.LingZhuAmount > 0) + CollectibleSpawner.SpawnLingZhu(worldPosition, picked.LingZhuAmount); } private static void ApplyDifficultyLingZhuScale(ref int lingZhu)