diff --git a/Assets/MyGame/Scenes/UIScene.unity b/Assets/MyGame/Scenes/UIScene.unity index 39543a147..60720ca70 100644 --- a/Assets/MyGame/Scenes/UIScene.unity +++ b/Assets/MyGame/Scenes/UIScene.unity @@ -3690,7 +3690,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!114 &1096182886 MonoBehaviour: m_ObjectHideFlags: 0 @@ -6398,7 +6398,7 @@ MonoBehaviour: spawnList: [] isCreateFish: 0 isFrozen: 0 - debugSpawnFishNumber: 12032 + debugSpawnFishNumber: 12029 fishList_All: [] fishList_Small: [] fishList_Boss: [] @@ -6845,6 +6845,11 @@ PrefabInstance: propertyPath: m_Name value: PW_Prop_IronFist objectReference: {fileID: 0} + - target: {fileID: 6379684486006968571, guid: 9b8be0fc8702c6546bdb3fce2d1f479f, + type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} - target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f, type: 3} propertyPath: m_LocalPosition.x @@ -7119,6 +7124,79 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 +--- !u!1001 &4272855452577043047 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalPosition.x + value: 3.2313976 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalPosition.y + value: 1.60395 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalPosition.z + value: -1.430045 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3363739725897090535, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_Name + value: GameObject + objectReference: {fileID: 0} + - target: {fileID: 3363739725897090535, guid: 97aa30e2785dc6b4a8857b2718fedf53, + type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 97aa30e2785dc6b4a8857b2718fedf53, type: 3} --- !u!224 &4559688231163668212 RectTransform: m_ObjectHideFlags: 0 @@ -7918,3 +7996,4 @@ SceneRoots: - {fileID: 841547336076769388} - {fileID: 1328183416056466136} - {fileID: 2518911503280687070} + - {fileID: 4272855452577043047} diff --git a/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs b/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs index 24ff11b91..c1371c9c1 100644 --- a/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs +++ b/Assets/MyGame/Scripts/Characters/Monster/MonsterContral.cs @@ -289,7 +289,12 @@ public class MonsterContral : MonoBehaviour LoadHitEffect(); baseMmove = isMove; } - public async void LoadHitEffect() + /// + /// 查找受击特效子物体并强制隐藏。 + /// 原为 async void(无 await 实际同步执行),现改为普通方法; + /// Awake 和每次 OnEnable 都会调用,保证池回收后不残留激活状态。 + /// + public void LoadHitEffect() { // 查找受击特效子物体并默认隐藏 var hitTra = FindDeepChild(transform, "HitEffect"); @@ -301,6 +306,14 @@ public class MonsterContral : MonoBehaviour } public virtual void OnEnable() { + // ⭐ 每次 OnEnable 重新查找并强制隐藏受击特效。 + // 根因:HurtCoroutine 激活 hurt 后等 0.2s 再关闭,若鱼在这期间被 + // 击杀回收(GO 停用 → 协程中断),hurt 会残留激活状态; + // 而 LoadHitEffect 原来只在 Awake 调用一次(池化对象不重跑 Awake), + // 重新生成时不会恢复 → 鱼带着受击特效出场。 + // 另外池回收的鱼 transform 可能更换子层级,重新查找更稳妥。 + LoadHitEffect(); + // ⭐ 用 baseMmove 恢复 isMove:Awake 时记录预制体原始 isMove 状态。 // - 普通鱼预制体 isMove=true → 池回收后恢复 true,正常游动 // (之前被注释导致:冰冻时 FreezeAllFish 设 isMove=false → 鱼回收 → diff --git a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs b/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs deleted file mode 100644 index 0e06d275f..000000000 --- a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs +++ /dev/null @@ -1,588 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -// ============================================================ -// 文件:BossConfig.cs -// 职责:Boss 各种死亡爆奖配置(幸运轮盘/小丑扑克/幸运飞碟/破坏球/烈焰风暴/星际巡航/神龙转盘 等) -// - 服务端下发配置,客户端解析后用 GetResponse() 取随机结果 -// - 已将服务端依赖(GlobalRandom/RandomBossOption/BsonIgnoreExtraElements) -// 替换为 Unity 客户端兼容实现 -// ============================================================ - -namespace Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass -{ - /// - /// Boss设定配置信息 - /// - public class BossConfig - { - /// 幸运轮盘配置信息 - public List LuckWheel { get; set; } = new List(); - - /// 小丑扑克 - public LuckPokerConfig LuckPoker { get; set; } = new LuckPokerConfig(); - - /// 幸运飞碟 - public List LuckFlyDisk { get; set; } = new List(); - - /// 全屏秒怪 - public BaseBossConfig FullScreen { get; set; } = new BaseBossConfig(); - - /// 范围秒怪 - public BaseBossConfig Range { get; set; } = new BaseBossConfig(); - - /// 弹药箱配置 - public AmmunitionBoxConfig AmmunitionBox { get; set; } = new AmmunitionBoxConfig(); - - /// 星际巡航配置 - public InterstellarCruiseConfig InterstellarCruise { get; set; } = new InterstellarCruiseConfig(); - - /// 烈焰风暴-死亡配置 - public BossFlameStormConfig FlameStorm { get; set; } = new BossFlameStormConfig(); - - /// 破坏球-死亡配置 - public BossBombConfig Bomb { get; set; } = new BossBombConfig(); - - /// 概率击杀 - public List Probability { get; set; } = new List(); - - /// 神龙转盘 - public List LuckDragon { get; set; } = new List(); - - /// - /// 根据权重随机获取一个 Boss 选项 - /// - public static int GetBossProbabilityConfigResponse(List configParams) - { - if (configParams == null || configParams.Count == 0) return 0; - - int totalWeight = configParams.Sum(p => p.TriggerRate); - if (totalWeight <= 0) return 0; - - int randomValue = GlobalRandom.Next(0, totalWeight); - int currentWeightSum = 0; - foreach (var param in configParams) - { - currentWeightSum += param.TriggerRate; - if (randomValue < currentWeightSum) - { - return GlobalRandom.NextInclusive(param.Min, param.Max); - } - } - return 0; - } - - /// - /// 根据权重随机获取一个死亡次数配置 - /// - public static CruiseConfigCount GetRandomCountConfigOption(List options) - { - if (options == null || !options.Any()) return null; - - long totalWeight = options.Sum(o => (long)o.TriggerRate); - if (totalWeight <= 0) return null; - - long randomValue = GlobalRandom.NextInt64(0, totalWeight); - long currentWeightSum = 0; - foreach (var option in options) - { - currentWeightSum += option.TriggerRate; - if (randomValue < currentWeightSum) - { - return option; - } - } - return options.FirstOrDefault(o => o.TriggerRate > 0); - } - - /// 死亡次数配置参数 - public class CruiseConfigCount - { - /// 死亡次数 - public int Count { get; set; } - - /// 触发权重 - public int TriggerRate { get; set; } = 0; - - /// 击杀权重 - public int KillRate { get; set; } = 0; - } - - /// 神龙转盘 - public class LuckDragonConfig : BaseBossConfig - { - /// 外圈配置 下一个配置为-1 - public List OuterConfig { get; set; } = new List(); - - /// 中圈配置 下一个配置为-1 - public List MiddleConfig { get; set; } = new List(); - - /// 内圈配置 下一个配置为-1 - public List InnerConfig { get; set; } = new List(); - - /// 获取结果 - public (List option, int beizhu) GetResponse() - { - int beishu = 1; - var result = new List(); - int outerResult = GetBossProbabilityConfigResponse(OuterConfig); - result.Add(outerResult); - if (outerResult == -1) - { - int middleResult = GetBossProbabilityConfigResponse(MiddleConfig); - result.Add(middleResult); - if (outerResult == -1) - { - int innerResult = GetBossProbabilityConfigResponse(InnerConfig); - result.Add(innerResult); - beishu = innerResult; - } - else - { - beishu = middleResult; - } - } - else - { - beishu = outerResult; - } - UnityEngine.Debug.Log($"[BossConfig] LuckDragon.GetResponse 选项=[{string.Join(",", result)}] 倍数={beishu}"); - return (result, beishu); - } - } - - /// 破坏球配置参数 - public class BossBombConfig : BaseBossConfig - { - /// 死亡次数配置 - public List CountConfig { get; set; } = new List(); - - /// 第一次死亡配置 - public List OneDeathConfig { get; set; } = new List(); - - /// 第二次死亡配置 - public List TwoDeathConfig { get; set; } = new List(); - - /// 获取破坏球配置响应信息 - public (int beishu, int type) GetResponse(string fishId) - { - int beishu = 0; - var countConfig = GetRandomCountConfigOption(CountConfig); - if (countConfig == null) - { - UnityEngine.Debug.Log("[BossConfig] Bomb.GetResponse countConfig为null 返回 (1,1)"); - return (1, 1); - } - if (countConfig.Count == 1) - { - beishu = GetBossProbabilityConfigResponse(OneDeathConfig); - UnityEngine.Debug.Log($"[BossConfig] Bomb.GetResponse 死亡次数={countConfig.Count} 倍数={beishu} type=1 fishId={fishId}"); - return (beishu, 1); - } - else - { - beishu = GetBossProbabilityConfigResponse(TwoDeathConfig); - UnityEngine.Debug.Log($"[BossConfig] Bomb.GetResponse 死亡次数={countConfig.Count} 倍数={beishu} type=2 fishId={fishId}"); - return (beishu, 2); - } - } - } - - /// 烈焰风暴配置 - public class BossFlameStormConfig : BaseBossConfig - { - /// 死亡次数配置 - public List CountConfig { get; set; } = new List(); - - /// 第一次死亡配置 - public List OneDeathConfig { get; set; } = new List(); - - /// 第二次死亡配置 - public List TwoDeathConfig { get; set; } = new List(); - - /// 获取烈焰风暴配置响应信息 - public (bool isKill, int beishu, string fishId) GetResponse(string fishId) - { - bool isKill = false; - int beishu = 0; - int count = 1; - int sumcount = 1; - - if (!fishId.Contains("-")) // 首次击杀 - { - var countConfig = GetRandomCountConfigOption(CountConfig); - if (countConfig == null) - { - UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 首击 countConfig为null 返回 (true,1,{fishId})"); - return (true, 1, fishId); - } - count = countConfig.Count; - beishu = GetBossProbabilityConfigResponse(OneDeathConfig); - if (count == 1) - { - isKill = true; - UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 首击一次死 isKill=true 倍数={beishu} fishId={fishId}-{count}-{sumcount}"); - return (isKill, beishu, $"{fishId}-{count}-{sumcount}"); - } - else - { - sumcount = countConfig.Count; - } - } - else - { - var parts = fishId.Split('-'); - count = int.Parse(parts[1]); - sumcount = int.Parse(parts[2]); - } - if (count == 1) - { - beishu = GetBossProbabilityConfigResponse(TwoDeathConfig); - if (sumcount == 2 && count == 1) - { - UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 二击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}"); - return (true, beishu, $"{fishId}-{count + 1}-{sumcount}"); - } - else - { - UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 二击未死 isKill=false 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}"); - return (false, beishu, $"{fishId}-{count + 1}-{sumcount}"); - } - } - UnityEngine.Debug.Log($"[BossConfig] FlameStorm.GetResponse 三击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}"); - return (true, beishu, $"{fishId}-{count + 1}-{sumcount}"); - } - } - - /// 星际巡航配置 - public class InterstellarCruiseConfig : BaseBossConfig - { - /// 死亡次数配置 - public List CountConfig { get; set; } = new List(); - - /// 第一次死亡配置 - public List OneDeathConfig { get; set; } = new List(); - - /// 第二次死亡配置 - public List TwoDeathConfig { get; set; } = new List(); - - /// 第三次死亡配置 - public List ThreeDeathConfig { get; set; } = new List(); - - /// 获取星际巡航配置响应信息 - public (bool isKill, int beishu, string fishId) GetResponse(string fishId) - { - bool isKill = false; - int beishu = 0; - int count = 1; - int sumcount = 1; - - if (!fishId.Contains("-")) // 首次击杀 - { - var countConfig = GetRandomCountConfigOption(CountConfig); - if (countConfig == null) - { - UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 首击 countConfig为null 返回 (true,1,{fishId})"); - return (true, 1, fishId); - } - count = countConfig.Count; - beishu = GetBossProbabilityConfigResponse(OneDeathConfig); - if (count == 1) - { - isKill = true; - UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 首击一次死 isKill=true 倍数={beishu} fishId={fishId}-{count}-{sumcount}"); - return (isKill, beishu, $"{fishId}-{count}-{sumcount}"); - } - else - { - sumcount = countConfig.Count; - } - } - else - { - var parts = fishId.Split('-'); - count = int.Parse(parts[1]); - sumcount = int.Parse(parts[2]); - } - if (count == 1) - { - beishu = GetBossProbabilityConfigResponse(TwoDeathConfig); - if (sumcount == 2 && count == 1) - { - UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 二击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}"); - return (true, beishu, $"{fishId}-{count + 1}-{sumcount}"); - } - else - { - UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 二击未死 isKill=false 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}"); - return (false, beishu, $"{fishId}-{count + 1}-{sumcount}"); - } - } - beishu = GetBossProbabilityConfigResponse(ThreeDeathConfig); - UnityEngine.Debug.Log($"[BossConfig] Cruise.GetResponse 三击致死 isKill=true 倍数={beishu} fishId={fishId}-{count + 1}-{sumcount}"); - return (true, beishu, $"{fishId}-{count + 1}-{sumcount}"); - } - } - - /// 概率击杀 - public class BossProbabilityConfig : BaseBossConfig - { - public List configParams { get; set; } = new List(); - - public int GetResponse() - { - int beishu = GetBossProbabilityConfigResponse(configParams); - UnityEngine.Debug.Log($"[BossConfig] Probability.GetResponse 倍数={beishu}"); - return beishu; - } - } - - /// 弹药箱配置 - public class AmmunitionBoxConfig : BaseBossConfig - { - /// 3个一样的 - public List OptionList { get; set; } = new List(); - - /// 获取随机结果 - public List GetResponse() - { - var opt = RandomBossOption.GetRandomBossOption(OptionList); - if (opt == null) - { - UnityEngine.Debug.LogWarning("[BossConfig] AmmunitionBox.GetResponse 选中为null"); - return null; - } - UnityEngine.Debug.Log($"[BossConfig] AmmunitionBox.GetResponse 选项Id={opt.OptionId} 倍数/分值={opt.Score}"); - return new List() { opt }; - } - } - - /// 幸运飞碟配置信息 - public class LuckFlyDiskConfig : BaseBossConfig - { - /// 内层配置选项列表 - public List InnerOptionList { get; set; } = new List(); - - /// 外层配置选项列表 - public List OuterOptionList { get; set; } = new List(); - - /// 获取随机结果 - public List GetResponse() - { - List result = new List(); - var opt = RandomBossOption.GetRandomBossOption(InnerOptionList); - result.Add(opt); - var opt1 = RandomBossOption.GetRandomBossOption(OuterOptionList); - result.Add(opt1); - UnityEngine.Debug.Log($"[BossConfig] FlyDisk.GetResponse 内层={(opt?.OptionId.ToString() ?? "null")} 外层={(opt1?.OptionId.ToString() ?? "null")}"); - return result; - } - } - - /// 小丑扑克 - public class LuckPokerConfig : BaseBossConfig - { - /// 配置选项列表 - public List OptionList { get; set; } = new List(); - - /// 获取随机结果 - public List GetResponse() - { - var opt = RandomBossOption.GetRandomBossOption(OptionList); - if (opt == null) - { - UnityEngine.Debug.LogWarning("[BossConfig] Poker.GetResponse 选中为null"); - return null; - } - UnityEngine.Debug.Log($"[BossConfig] Poker.GetResponse 选项Id={opt.OptionId} 倍数/分值={opt.Score}"); - return new List() { opt }; - } - } - - /// 幸运轮盘配置信息 - public class LuckWheelConfig : BaseBossConfig - { - /// 配置选项列表 - public List OptionList { get; set; } = new List(); - - /// 配置项数量配置列表 - public List CountList { get; set; } = new List(); - - /// 获取随机结果 - public List GetResponse() - { - List count = new List(); - List option = new List(); - - foreach (var item in CountList) - { - if (item.TriggerRate >= 100) - { - count.Add(item.OptionId); - continue; - } - if (GlobalRandom.Next(100) < item.TriggerRate) - { - count.Add(item.OptionId); - continue; - } - break; - } - foreach (var item in count) - { - var opt = RandomBossOption.GetRandomBossOption(OptionList); - if (opt == null) continue; - option.Add(opt); - } - UnityEngine.Debug.Log($"[BossConfig] Wheel.GetResponse 触发次数={count.Count} 选项Ids=[{string.Join(",", option.Select(o => o.OptionId))}]"); - return option; - } - } - - /// Boss配置基类 - public class BaseBossConfig - { - /// 鱼编号 - public List FishNumber { get; set; } = new List(); - } - - /// boss 概率配置参数 - public class BossProbabilityConfigParam - { - public BossProbabilityConfigParam() { } - - public BossProbabilityConfigParam(int min, int max, int triggerRate) - { - Min = min; - Max = max; - TriggerRate = triggerRate; - } - - /// 最小值 - public int Min { get; set; } - - /// 最大值 - public int Max { get; set; } - - /// 触发权重 - public int TriggerRate { get; set; } = 0; - } - } - - /// Boss道具掉落配置项 - public class BossDropItemConfig - { - /// 道具编号 - public string PropNumber { get; set; } = string.Empty; - - /// 道具名称 - public string PropName { get; set; } = string.Empty; - - /// 掉落数量 - public int Count { get; set; } = 1; - - /// 掉落权重(概率 = Weight / 10000) - public int Weight { get; set; } = 0; - } - - /// Boss道具掉落配置 - public class BossDropConfig - { - /// 不掉落权重(概率 = NoDropWeight / 总权重和) - public int NoDropWeight { get; set; } = 5000; - - /// 掉落道具列表 - public List DropItems { get; set; } = new List(); - } - - /// 公共选项配置 - public class BossOptionBaseParam - { - public BossOptionBaseParam() { } - - public BossOptionBaseParam(double optionId, int triggerRate, double score = 0) - { - OptionId = optionId; - TriggerRate = triggerRate; - Score = score; - } - - /// 选项编号 - public double OptionId { get; set; } - - /// 触发权重 - public int TriggerRate { get; set; } = 0; - - /// 分值 - public double Score { get; set; } = 0; - } - - // ============================================================ - // 服务端依赖的 Unity 客户端兼容实现 - // ============================================================ - - /// - /// 线程安全的随机数工具(替代服务端的 GlobalRandom)。 - /// 全部走 UnityEngine.Random,保证客户端单线程主逻辑使用。 - /// - public static class GlobalRandom - { - /// [min, max) 的随机整数 - public static int Next(int min, int max) - { - return UnityEngine.Random.Range(min, max); - } - - /// [0, max) 的随机整数 - public static int Next(int max) - { - return UnityEngine.Random.Range(0, max); - } - - /// [min, max] 闭区间的随机整数(含两端) - public static int NextInclusive(int min, int max) - { - // Range 的整数重载是 [min, max) 上界开,这里补 1 实现闭区间 - if (min > max) return min; - return UnityEngine.Random.Range(min, max + 1); - } - - /// [min, max) 的随机 long - public static long NextInt64(long min, long max) - { - if (min >= max) return min; - // UnityEngine.Random 无 long 重载,用 double 映射 - double t = UnityEngine.Random.value; - return (long)(min + (max - min) * t); - } - } - - /// - /// Boss 选项权重随机工具(替代服务端的 RandomBossOption)。 - /// - public static class RandomBossOption - { - /// - /// 按权重随机选中一个 Boss 选项。 - /// - public static BossOptionBaseParam GetRandomBossOption(List options) - { - if (options == null || options.Count == 0) return null; - - long totalWeight = options.Sum(o => (long)o.TriggerRate); - if (totalWeight <= 0) return null; - - long randomValue = GlobalRandom.NextInt64(0, totalWeight); - long currentWeightSum = 0; - foreach (var option in options) - { - currentWeightSum += option.TriggerRate; - if (randomValue < currentWeightSum) - { - return option; - } - } - return options.FirstOrDefault(o => o.TriggerRate > 0); - } - } -} diff --git a/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs new file mode 100644 index 000000000..b535849cc --- /dev/null +++ b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs @@ -0,0 +1,288 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; + +// ============================================================ +// 文件:BossKillParam.cs +// 职责:Boss 爆奖(击杀奖励)param 的客户端专用解析模型。 +// 对应《Boss爆浆数据前端对接文档》第三节各 Boss 的 param 结构。 +// 所有数据由服务端 RoomKillNotice.param 直接下发,客户端只负责 +// 解析和渲染,不做任何随机计算(旧 BossConfig 的 GetResponse 已全部删除)。 +// +// param 结构速查(按 Boss 类型): +// 1. 幸运轮盘/小丑扑克/弹药箱 → { res:[{optionId,triggerRate,score}], count } 总倍数=score之和 +// 2. 幸运飞碟 → { res:[内层,外层], count:2 } 总倍数=内层×外层 +// 3. 星际巡航/烈焰风暴 → { isKill, beishu, fishId } 多次死亡 +// 4. 破坏球 → { beishu, type } type=2 为最终死亡 +// 5. 神龙转盘 → { res:{ option:[...], beizhu } } beizhu=最终倍数 +// 6. 概率击杀 → param 直接是整数(倍数) +// 7. 全屏/范围秒怪 → param = null +// ============================================================ + +namespace Assets.MyGame.Scripts.Net.WebResponses +{ + /// Boss 爆奖 param 类型(由 BossKillParamParser.DetectType 判定) + public enum BossKillParamType + { + /// 无 param(普通鱼 / 全屏秒怪 / 范围秒怪) + None = 0, + + /// 选项数组类:幸运轮盘 / 小丑扑克 / 幸运飞碟 / 弹药箱(res 是数组) + Options = 1, + + /// 多次死亡:星际巡航 / 烈焰风暴(含 isKill + fishId) + MultiDeath = 2, + + /// 破坏球(含 type,无 isKill) + Bomb = 3, + + /// 神龙转盘(res 是对象,含 option 数组) + Dragon = 4, + + /// 概率击杀(param 直接是整数倍数) + Probability = 5, + } + + /// + /// 选项数组项:幸运轮盘/小丑扑克/幸运飞碟/弹药箱的 res 数组元素。 + /// JSON: { "optionId": 2, "triggerRate": 30, "score": 3 } + /// + [Serializable] + public class BossKillOption + { + /// 选项编号(转盘位置/扑克牌编号/飞碟内外层索引) + public double optionId; + + /// 触发权重(客户端一般用不到,仅透传) + public int triggerRate; + + /// 该项倍数/分值 + public double score; + + public BossKillOption() { } + + public BossKillOption(double optionId, int triggerRate, double score = 0) + { + this.optionId = optionId; + this.triggerRate = triggerRate; + this.score = score; + } + } + + /// + /// 选项数组类 param:幸运轮盘/小丑扑克/幸运飞碟/弹药箱。 + /// JSON: { "res": [...], "count": N } + /// + [Serializable] + public class BossOptionsParam + { + /// 选中的选项数组(长度=转动/抽取次数;飞碟固定2:res[0]=内层 res[1]=外层) + public List res = new List(); + + /// 选项个数(= res.Length) + public int count; + } + + /// + /// 多次死亡 param:星际巡航(最多3次)/ 烈焰风暴(最多2次)。 + /// JSON: { "isKill": true, "beishu": 155, "fishId": "13009-3-3" } + /// + [Serializable] + public class BossMultiDeathParam + { + /// true=最终击杀(鱼死亡爆炸);false=未死(鱼复活继续打) + public bool isKill; + + /// 本次奖励倍数 + public int beishu; + + /// 鱼ID,格式:原ID-总次数-当前次数(如 13009-3-2) + public string fishId = ""; + + /// 从 fishId 解析总死亡次数(解析失败返回 0) + public int TotalCount + { + get + { + var parts = fishId?.Split('-'); + return parts != null && parts.Length >= 3 && int.TryParse(parts[1], out int v) ? v : 0; + } + } + + /// 从 fishId 解析当前第几次死亡(解析失败返回 0) + public int CurrentCount + { + get + { + var parts = fishId?.Split('-'); + return parts != null && parts.Length >= 3 && int.TryParse(parts[2], out int v) ? v : 0; + } + } + } + + /// + /// 破坏球 param。 + /// JSON: { "beishu": 420, "type": 1 } + /// + [Serializable] + public class BossBombParam + { + /// 本次奖励倍数 + public int beishu; + + /// 死亡类型:1=第一次死亡(鱼继续存活),2=第二次死亡(最终死亡,鱼爆炸) + public int type; + + /// 是否最终死亡(type==2) + public bool IsFinalKill => type >= 2; + } + + /// + /// 神龙转盘 param。 + /// JSON: { "res": { "option": [80, 160], "beizhu": 160 } } + /// option 数组长度=停靠圈数(1~3):外圈先判定,-1 则继续中圈,再 -1 判定内圈。 + /// + [Serializable] + public class BossDragonParam + { + /// 转盘结果(内层结构) + public DragonRes res = new DragonRes(); + + [Serializable] + public class DragonRes + { + /// 各圈数值结果(外→中→内,-1 表示未停靠该圈) + public List option = new List(); + + /// 最终倍数(取最内层已停靠圈的数值) + public int beizhu; + } + } + + // ============================================================ + // 解析器 + // ============================================================ + + /// + /// BossKillNotice.param 解析器(客户端专用,只解析不随机)。 + /// 用法: + /// var type = BossKillParamParser.DetectType(notice.param); + /// switch (type) { + /// case BossKillParamType.MultiDeath: var p = BossKillParamParser.ParseMultiDeath(notice.param); ... + /// } + /// + public static class BossKillParamParser + { + /// + /// 判定 param 类型(对齐文档第四节 JS 判定逻辑)。 + /// + public static BossKillParamType DetectType(JToken param) + { + if (param == null || param.Type == JTokenType.Null) + return BossKillParamType.None; + + // 整数 = 概率击杀 + if (param.Type == JTokenType.Integer || param.Type == JTokenType.Float) + return BossKillParamType.Probability; + + if (param is JObject obj) + { + // 多次死亡:isKill + fishId + if (obj["isKill"] != null && obj["fishId"] != null) + return BossKillParamType.MultiDeath; + + // 破坏球:type + if (obj["type"] != null) + return BossKillParamType.Bomb; + + // 神龙转盘:res 是对象且含 option + if (obj["res"] is JObject resObj && resObj["option"] != null) + return BossKillParamType.Dragon; + + // 选项数组类:res 是数组 + if (obj["res"] is JArray) + return BossKillParamType.Options; + } + + return BossKillParamType.None; + } + + /// 解析选项数组类(幸运轮盘/小丑扑克/幸运飞碟/弹药箱),失败返回空对象 + public static BossOptionsParam ParseOptions(JToken param) + { + try + { + if (param is JObject obj) + { + var result = obj.ToObject(); + if (result != null) return result; + } + } + catch (Exception e) + { + UnityEngine.Debug.LogWarning($"[BossKillParam] ParseOptions 失败: {e.Message}"); + } + return new BossOptionsParam(); + } + + /// 解析多次死亡(星际巡航/烈焰风暴),失败返回 null + public static BossMultiDeathParam ParseMultiDeath(JToken param) + { + try + { + if (param is JObject obj) + return obj.ToObject(); + } + catch (Exception e) + { + UnityEngine.Debug.LogWarning($"[BossKillParam] ParseMultiDeath 失败: {e.Message}"); + } + return null; + } + + /// 解析破坏球,失败返回 null + public static BossBombParam ParseBomb(JToken param) + { + try + { + if (param is JObject obj) + return obj.ToObject(); + } + catch (Exception e) + { + UnityEngine.Debug.LogWarning($"[BossKillParam] ParseBomb 失败: {e.Message}"); + } + return null; + } + + /// 解析神龙转盘,失败返回 null + public static BossDragonParam ParseDragon(JToken param) + { + try + { + if (param is JObject obj) + return obj.ToObject(); + } + catch (Exception e) + { + UnityEngine.Debug.LogWarning($"[BossKillParam] ParseDragon 失败: {e.Message}"); + } + return null; + } + + /// 解析概率击杀(param 直接是整数倍数),失败返回 0 + public static int ParseProbability(JToken param) + { + try + { + if (param != null && (param.Type == JTokenType.Integer || param.Type == JTokenType.Float)) + return (int)param.Value(); + } + catch (Exception e) + { + UnityEngine.Debug.LogWarning($"[BossKillParam] ParseProbability 失败: {e.Message}"); + } + return 0; + } + } +} diff --git a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs.meta b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs.meta similarity index 83% rename from Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs.meta rename to Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs.meta index 37b1ee58c..da7329379 100644 --- a/Assets/MyGame/Scripts/Net/APIResponses/GameConfig_SubClass/BossConfig.cs.meta +++ b/Assets/MyGame/Scripts/Net/WebResponses/BossKillParam.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 69ace07c67208384189ccb057cbecba5 +guid: 46b52b22a0770114bbc78dada374f6fe MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs b/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs index d167b6913..dd40ed85e 100644 --- a/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs +++ b/Assets/MyGame/Scripts/Net/WebResponses/RoomKillNotice.cs @@ -38,12 +38,14 @@ namespace Assets.MyGame.Scripts.Net.WebResponses public long fishScore; /// - /// Boss 爆奖结果(服务端按 Boss 类型下发不同结构)。 - /// 调用方按鱼类型用 ToObject<T>() 解析为具体结构: - /// - LuckDragon: 取 option(int 数组)、beishu - /// - Bomb: 取 beishu、type - /// - FlameStorm/Cruise: 取 isKill、beishu、fishId - /// - 选项类(Wheel/Poker/FlyDisk/AmmunitionBox): List<BossOptionBaseParam> + /// Boss 爆奖结果(服务端按 Boss 类型下发不同结构,客户端只解析不随机)。 + /// 用 BossKillParamParser.DetectType(param) 判定类型后按结构解析: + /// - Options : ParseOptions → BossOptionsParam(幸运轮盘/小丑扑克/幸运飞碟/弹药箱) + /// - MultiDeath : ParseMultiDeath → BossMultiDeathParam(星际巡航/烈焰风暴 isKill/beishu/fishId) + /// - Bomb : ParseBomb → BossBombParam(破坏球 beishu/type) + /// - Dragon : ParseDragon → BossDragonParam(神龙转盘 res.option/res.beizhu) + /// - Probability : ParseProbability → int(概率击杀,param 直接是倍数) + /// - None : 普通鱼 / 全屏秒怪 / 范围秒怪 /// public JToken param; diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs index f44849e83..57421b8bf 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/ChaoNengMoHe/ChaoNengMoHeEvent.cs @@ -1,4 +1,4 @@ -using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass; +using Assets.MyGame.Scripts.Net.WebResponses; using DG.Tweening; using Newtonsoft.Json.Linq; using System; @@ -11,7 +11,7 @@ using UnityEngine.UI; public class ChaoNengMoHeEvent : BJEventBase { /// Boss 死亡时传来的特殊值(服务端 res 数组),与幸运轮一致 - private List _cardParams = new List(); + private List _cardParams = new List(); /// 倍数列表(Inspector 拖入,8 个) public List obj_BeiShu = new List(); @@ -73,19 +73,19 @@ public class ChaoNengMoHeEvent : BJEventBase JToken resToken = rootToken["res"] ?? rootToken; if (resToken is JArray jarr) - _cardParams = jarr.ToObject>() ?? new List(); + _cardParams = jarr.ToObject>() ?? new List(); else if (resToken is JObject jobj) - _cardParams = new List { jobj.ToObject() }; + _cardParams = new List { jobj.ToObject() }; else - _cardParams = new List(); + _cardParams = new List(); } catch (Exception e) { Debug.LogError($"[ChaoNengMoHe] 解析参数失败:{e.Message}; 原始={obj}"); - _cardParams = new List(); + _cardParams = new List(); } - Debug.Log($"[ChaoNengMoHe] 解析到 {_cardParams.Count} 个选项: [{string.Join(", ", _cardParams.Select(p => p.Score))}]"); + Debug.Log($"[ChaoNengMoHe] 解析到 {_cardParams.Count} 个选项: [{string.Join(", ", _cardParams.Select(p => p.score))}]"); } /// Timeline 结束触发:无爆奖,直接播放 bjEndUI 并退出 public void TimeLineEnd() @@ -132,7 +132,7 @@ public class ChaoNengMoHeEvent : BJEventBase obj_BeiShu[0].transform.parent.gameObject.SetActive(true); // 如果没有服务端数据,用默认倍数兜底 var sourceScores = _cardParams != null && _cardParams.Count > 0 - ? _cardParams.Select(p => (int)p.Score).ToList() + ? _cardParams.Select(p => (int)p.score).ToList() : defaultBeishu.ToList(); // 随机打乱源数据 diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs index d1d5f80fe..c5e077744 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XiaoChouPuKe/XiaoChouPuKeEvent.cs @@ -1,4 +1,4 @@ -using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass; +using Assets.MyGame.Scripts.Net.WebResponses; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -57,7 +57,7 @@ public class XiaoChouPuKeEvent : BJEventBase private const int AWARD_SANPAI = 6; // 散排 /// 服务端下发的奖项数据(通常只有 1 个元素) - private List _cardParams = new List(); + private List _cardParams = new List(); /// 本次奖项类型(1-6) private int _awardType = AWARD_SANPAI; @@ -105,7 +105,7 @@ public class XiaoChouPuKeEvent : BJEventBase // ============================================================ /// - /// 把 obj(RoomKillNotice.param)解析为 List<BossOptionBaseParam>。 + /// 把 obj(RoomKillNotice.param)解析为 List<BossKillOption>。 /// 服务端格式:{ "res": [{optionId, triggerRate, score}], "count": 1 } /// private void ParseCardParams() @@ -113,7 +113,7 @@ public class XiaoChouPuKeEvent : BJEventBase if (obj == null) { Debug.LogWarning("[XiaoChouPuKe] param 为 null,使用默认散排"); - _cardParams = new List(); + _cardParams = new List(); return; } @@ -123,23 +123,23 @@ public class XiaoChouPuKeEvent : BJEventBase JToken resToken = rootToken["res"] ?? rootToken; if (resToken is JArray) - _cardParams = resToken.ToObject>() ?? new List(); + _cardParams = resToken.ToObject>() ?? new List(); else if (resToken is JObject jobj) - _cardParams = new List { jobj.ToObject() }; + _cardParams = new List { jobj.ToObject() }; else - _cardParams = new List(); + _cardParams = new List(); } catch (Exception e) { Debug.LogError($"[XiaoChouPuKe] 解析卡牌数据失败:{e.Message};原始={obj}"); - _cardParams = new List(); + _cardParams = new List(); } // 读取奖项类型和倍数 if (_cardParams.Count > 0 && _cardParams[0] != null) { - _awardType = Mathf.Clamp((int)_cardParams[0].OptionId, 1, 6); - _awardScore = (int)_cardParams[0].Score; + _awardType = Mathf.Clamp((int)_cardParams[0].optionId, 1, 6); + _awardScore = (int)_cardParams[0].score; } else { diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs index f2a3b30ab..0128b5574 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingJiXunHang/XingJiXunHang_BOSS.cs @@ -1,4 +1,3 @@ -using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass; using Assets.MyGame.Scripts.Net.WebResponses; using Newtonsoft.Json.Linq; using System; @@ -8,19 +7,16 @@ using UnityEngine; /// /// 星际巡航 Boss(继承 MonsterControl_BossBase)。 /// -/// 支持多次死亡(1~3次,服务端配置决定): +/// 支持多次死亡(1~3次,服务端决定): /// 非最终死亡 → 显示 BJEndUI(倍数+分数),Boss 不消失,等待下次击杀 -/// 最终死亡 → 触发完整爆奖流程 + 道具武器掉落 +/// 最终死亡 → isKill=true 直接删除 Boss + 触发完整爆奖流程 + 道具武器掉落 /// /// 死亡判定来源: -/// 方式1(优先):从 RoomKillNotice.param 解析 isKill/beishu/fishId(服务端下发) -/// 方式2(兜底):调用 InterstellarCruiseConfig.GetResponse(fishId) 客户端计算 +/// 方式1(优先):BossKillParamParser.ParseMultiDeath 解析 RoomKillNotice.param +/// { "isKill": bool, "beishu": int, "fishId": "原ID-总次数-当前次数" } +/// 方式2(兜底):param 缺失时按 maxDeathCount 简单判定死亡次数 /// -/// fishId 格式:原ID-总次数-当前次数(由 InterstellarCruiseConfig.GetResponse 管理) -/// 例:4000-3-2 表示总共3次,当前第2次 -/// -/// ⭐ 非最终死亡时不从鱼列表删除 Boss,等最终死亡爆奖流程结束后, -/// 由 XingJiXunHangEvent.die() 通知 Boss 回收。 +/// ⭐ 非最终死亡时不从鱼列表删除 Boss;最终死亡时下一帧直接 Id_DieFish_NotFX 删除。 /// public class XingJiXunHang_BOSS : MonsterControl_BossBase { @@ -34,15 +30,12 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase public float resumeMoveDelay = 2f; [Header("星际巡航 - 服务端参数解析")] - [Tooltip("是否从 param 解析 isKill(关闭则用客户端配置计算)")] + [Tooltip("是否从 param 解析 isKill(关闭则用 maxDeathCount 客户端兜底判定)")] public bool useServerParam = true; [Header("星际巡航 - 客户端兜底配置")] - [Tooltip("星际巡航死亡配置(兜底用,服务端未下发 param 时使用)。留空则按 maxDeathCount 简单判定。")] - public BossConfig.InterstellarCruiseConfig cruiseConfig; - - [Tooltip("最大死亡次数(cruiseConfig 为空时生效,默认2次)")] - public int maxDeathCount = 2; + [Tooltip("最大死亡次数(param 缺失时生效,默认3次)")] + public int maxDeathCount = 3; // ==================== 运行时状态 ==================== @@ -101,16 +94,28 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase if (useServerParam && obj?.param != null) { - // 方式1:从服务端 param 解析 + // 方式1:BossKillParamParser 解析服务端 param Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次 param原文: {obj.param.ToString(Newtonsoft.Json.Formatting.None)}"); - (isKill, beishu) = ParseServerParam(obj.param); - Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(服务端) isKill={isKill} beishu={beishu} guid={guid}"); + var p = BossKillParamParser.ParseMultiDeath(obj.param); + if (p != null) + { + isKill = p.isKill; + beishu = p.beishu; + if (!string.IsNullOrEmpty(p.fishId)) + _cruiseFishId = p.fishId; + } + else + { + Debug.LogWarning("[XingJiXunHang] param 解析失败,走客户端兜底"); + (isKill, beishu) = GetClientFallback(obj); + } + Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(服务端) isKill={isKill} beishu={beishu} fishId={_cruiseFishId} guid={guid}"); } else { - // 方式2:调用客户端配置计算 - (isKill, beishu, _cruiseFishId) = GetClientConfigResponse(obj); - Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(客户端) isKill={isKill} beishu={beishu} fishId={_cruiseFishId}"); + // 方式2:客户端兜底(param 缺失时按 maxDeathCount 判定) + (isKill, beishu) = GetClientFallback(obj); + Debug.Log($"[XingJiXunHang] DieFish 第{_deathCount}次(客户端兜底) isKill={isKill} beishu={beishu}"); } if (!isKill) @@ -329,58 +334,15 @@ public class XingJiXunHang_BOSS : MonsterControl_BossBase // ==================== 参数解析 ==================== /// - /// 从服务端 param 解析 isKill 和 beishu。 - /// param 结构(JToken): - /// { "isKill": true/false, "beishu": 100, "fishId": "4000-3-2", "weaponID": 6 } + /// 客户端兜底判定(param 缺失或解析失败时使用): + /// 按 maxDeathCount 简单判定死亡次数(类似 LieYanFengBao 模式)。 /// - private (bool isKill, int beishu) ParseServerParam(JToken param) + private (bool isKill, int beishu) GetClientFallback(RoomKillNotice obj) { - bool isKill = true; - int beishu = 1; - - try - { - JToken root = param is JObject jo ? jo : JObject.Parse(param.ToString()); - - isKill = root["isKill"]?.Value() ?? true; - beishu = root["beishu"]?.Value() ?? 1; - - // 同步更新 _cruiseFishId(如果服务端返回了) - var fishIdToken = root["fishId"]; - if (fishIdToken != null) - _cruiseFishId = fishIdToken.Value(); - } - catch (Exception e) - { - Debug.LogWarning($"[XingJiXunHang] 解析 param 失败: {e.Message},使用默认值 isKill=true beishu=1"); - } - - return (isKill, beishu); - } - - /// - /// 调用客户端 InterstellarCruiseConfig.GetResponse 计算死亡结果。 - /// 用于服务端未下发 param 时的兜底方案。 - /// - private (bool isKill, int beishu, string fishId) GetClientConfigResponse(RoomKillNotice obj) - { - // 方式A:使用 Inspector 配置的 InterstellarCruiseConfig - if (cruiseConfig != null) - { - string currentFishId = string.IsNullOrEmpty(_cruiseFishId) - ? fishTypeID.ToString() - : _cruiseFishId; - - var result = cruiseConfig.GetResponse(currentFishId); - _cruiseFishId = result.fishId; - return result; - } - - // 方式B:cruiseConfig 为空,用简单死亡次数判定(类似 LieYanFengBao 模式) bool kill = _deathCount >= maxDeathCount; int bs = obj?.beishu > 0 ? (int)obj.beishu : 1; - Debug.Log($"[XingJiXunHang] 客户端兜底(无配置): 第{_deathCount}次/{maxDeathCount}次 isKill={kill} beishu={bs}"); - return (kill, bs, _cruiseFishId); + Debug.Log($"[XingJiXunHang] 客户端兜底: 第{_deathCount}次/{maxDeathCount}次 isKill={kill} beishu={bs}"); + return (kill, bs); } // ==================== 清理 ==================== diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs index 2a8622be5..6ef70a7c5 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunFeiDie/RotatePan_XJMH.cs @@ -1,4 +1,4 @@ -using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass; +using Assets.MyGame.Scripts.Net.WebResponses; using DG.Tweening; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -55,9 +55,9 @@ public class RotatePan_XJMH : BJEventBase private Tween _neiTween; /// 内层选项(服务端下发,OptionId=索引) - private BossOptionBaseParam _innerOpt; + private BossKillOption _innerOpt; /// 外层选项(服务端下发,OptionId=索引) - private BossOptionBaseParam _outerOpt; + private BossKillOption _outerOpt; /// 内圈实际倍数(从数组取) private float _innerBeishu = 10f; @@ -85,7 +85,7 @@ public class RotatePan_XJMH : BJEventBase /// private void ParseOptions() { - List opts = null; + List opts = null; if (obj != null) { @@ -95,9 +95,9 @@ public class RotatePan_XJMH : BJEventBase JToken resToken = rootToken["res"] ?? rootToken; if (resToken is JArray) - opts = resToken.ToObject>(); + opts = resToken.ToObject>(); else if (resToken is JObject jobj) - opts = new List { jobj.ToObject() }; + opts = new List { jobj.ToObject() }; } catch (Exception e) { @@ -108,22 +108,22 @@ public class RotatePan_XJMH : BJEventBase if (opts == null || opts.Count == 0) { Debug.LogWarning("[XingYunFeiDie] 选项数据为空,使用默认索引 0"); - _innerOpt = new BossOptionBaseParam(0, 0, 1); - _outerOpt = new BossOptionBaseParam(0, 0, 1); + _innerOpt = new BossKillOption(0, 0, 1); + _outerOpt = new BossKillOption(0, 0, 1); } else { - _innerOpt = opts.Count > 0 ? opts[0] : new BossOptionBaseParam(0, 0, 1); - _outerOpt = opts.Count > 1 ? opts[1] : new BossOptionBaseParam(0, 0, 1); + _innerOpt = opts.Count > 0 ? opts[0] : new BossKillOption(0, 0, 1); + _outerOpt = opts.Count > 1 ? opts[1] : new BossKillOption(0, 0, 1); } // 从数组按 OptionId 索引取实际倍数 - _innerBeishu = GetBeishuFromArray(innerBeishus, (int)_innerOpt.OptionId, 10f); - _outerBeishu = GetBeishuFromArray(outerBeishus, (int)_outerOpt.OptionId, 1f); + _innerBeishu = GetBeishuFromArray(innerBeishus, (int)_innerOpt.optionId, 10f); + _outerBeishu = GetBeishuFromArray(outerBeishus, (int)_outerOpt.optionId, 1f); _totalBeishu = _innerBeishu * _outerBeishu; - Debug.Log($"[XingYunFeiDie] 内层 OptionId={_innerOpt.OptionId} 倍数={_innerBeishu}"); - Debug.Log($"[XingYunFeiDie] 外层 OptionId={_outerOpt.OptionId} 倍数={_outerBeishu}"); + Debug.Log($"[XingYunFeiDie] 内层 OptionId={_innerOpt.optionId} 倍数={_innerBeishu}"); + Debug.Log($"[XingYunFeiDie] 外层 OptionId={_outerOpt.optionId} 倍数={_outerBeishu}"); Debug.Log($"[XingYunFeiDie] 总倍数={_totalBeishu}"); } @@ -159,17 +159,17 @@ public class RotatePan_XJMH : BJEventBase int innerCount = innerBeishus != null ? innerBeishus.Length : 1; Debug.Log($"[XingYunFeiDie] 数组长度: outerBeishus(外圈7项)={outerCount} innerBeishus(内圈10项)={innerCount}"); - Debug.Log($"[XingYunFeiDie] 服务端OptionId: 外圈={_outerOpt.OptionId} 内圈={_innerOpt.OptionId}"); + Debug.Log($"[XingYunFeiDie] 服务端OptionId: 外圈={_outerOpt.optionId} 内圈={_innerOpt.optionId}"); // 外圈:必须精确停在顶点(中心角度),不随机 - float waiTargetAngle = OptionIdToAngle((int)_outerOpt.OptionId, outerCount); - Debug.Log($"[XingYunFeiDie] 外圈目标角度: OptionId={_outerOpt.OptionId} count={outerCount} → {waiTargetAngle}°"); + float waiTargetAngle = OptionIdToAngle((int)_outerOpt.optionId, outerCount); + Debug.Log($"[XingYunFeiDie] 外圈目标角度: OptionId={_outerOpt.optionId} count={outerCount} → {waiTargetAngle}°"); // 内圈:可在选项范围内随机偏移(中心角度 ± 半角) - float neiCenterAngle = OptionIdToAngle((int)_innerOpt.OptionId, innerCount); + float neiCenterAngle = OptionIdToAngle((int)_innerOpt.optionId, innerCount); float neiHalfAngle = (360f / innerCount) / 2f; float neiTargetAngle = neiCenterAngle + Random.Range(-neiHalfAngle, neiHalfAngle); - Debug.Log($"[XingYunFeiDie] 内圈目标角度: OptionId={_innerOpt.OptionId} count={innerCount} 中心={neiCenterAngle}° 随机后={neiTargetAngle}°"); + Debug.Log($"[XingYunFeiDie] 内圈目标角度: OptionId={_innerOpt.optionId} count={innerCount} 中心={neiCenterAngle}° 随机后={neiTargetAngle}°"); // 先转内圈 bool neiDone = false; diff --git a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs index a09548f59..38920c7e9 100644 --- a/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs +++ b/Assets/MyGame/aa/Game/XJMH/Boss/XingYunLun/XingYunLunEvent.cs @@ -1,4 +1,4 @@ -using Assets.MyGame.Scripts.Net.APIResponses.GameConfig_SubClass; +using Assets.MyGame.Scripts.Net.WebResponses; using DG.Tweening; using Newtonsoft.Json.Linq; using System; @@ -50,7 +50,7 @@ public class XingYunLunEvent : BJEventBase private List _items = new List(); /// 服务端下发的选项列表(用于映射格子) - private List _cardParams = new List(); + private List _cardParams = new List(); /// 每个 item 的目标格子索引 private List _targetSlots = new List(); @@ -111,20 +111,20 @@ public class XingYunLunEvent : BJEventBase JToken resToken = rootToken["res"] ?? rootToken; if (resToken is JArray jarr) - _cardParams = jarr.ToObject>() ?? new List(); + _cardParams = jarr.ToObject>() ?? new List(); else if (resToken is JObject jobj) - _cardParams = new List { jobj.ToObject() }; + _cardParams = new List { jobj.ToObject() }; else - _cardParams = new List(); + _cardParams = new List(); } catch (Exception e) { Debug.LogError($"[XingYunLun] 解析参数失败:{e.Message};原始={obj}"); - _cardParams = new List(); + _cardParams = new List(); } Debug.Log($"[XingYunLun] 解析到 {_cardParams.Count} 个选项: " + - $"[{string.Join(", ", _cardParams.Select(p => p.Score))}]"); + $"[{string.Join(", ", _cardParams.Select(p => p.score))}]"); } /// @@ -139,7 +139,7 @@ public class XingYunLunEvent : BJEventBase { if (_cardParams[i] != null) { - int score = (int)_cardParams[i].Score; + int score = (int)_cardParams[i].score; int slotIdx = FindSlotByScore(score); _targetSlots.Add(slotIdx); Debug.Log($"[XingYunLun] item[{i}] score={score} → slot={slotIdx}");