diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index 39dc4290f..daa89bfb4 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -1370,32 +1370,44 @@ public class GameMainPanel_FishBase : GameMainPanel_Base { Vector2 startPos = sit.GetBulletStartPos(); - // ⭐ 三发 + 锁定 + 有多目标:每发子弹瞄准不同的目标 - if (isSanShe && isLock && fireTargetMonsterIDs != null && fireTargetMonsterIDs.Count > 0) + // ⭐ 三发 + 锁定:每发子弹优先瞄准对应目标,目标不足或失效则按默认角度发射 + // 必须保证三发子弹都创建,否则金币消耗和后端对不上 + if (isSanShe && isLock) { - for (int i = 0; i < 3 && i < fireTargetMonsterIDs.Count; i++) + // 三发默认角度(无目标时用):左 -20,中 0,右 +20 + float[] defaultAngles = { angle - 20, angle, angle + 20 }; + + for (int i = 0; i < 3; i++) { - // 按 GUID 查找目标 + string bulletId = i < bullitIDs.Count ? bullitIDs[i] : bullitIDs[0]; MonsterContral targetMonster = null; Transform targetHitPos = null; - if (CreateFishManager.Instance.fishDatas_hashCodekey.TryGetValue(fireTargetMonsterIDs[i], out var m) - && m != null && m.gameObject.activeInHierarchy) + + // 尝试按 GUID 查找目标 + if (fireTargetMonsterIDs != null && i < fireTargetMonsterIDs.Count) { - targetMonster = m; - // ⭐ 优先用 lockPoint(锁定锚点),其次 collider,兜底 transform - targetHitPos = ResolveLockTransform(m); + if (CreateFishManager.Instance.fishDatas_hashCodekey.TryGetValue(fireTargetMonsterIDs[i], out var m) + && m != null && m.gameObject.activeInHierarchy + && IsFishPathLockable(m)) + { + targetMonster = m; + targetHitPos = ResolveLockTransform(m); + } } if (targetMonster != null) { - // 计算朝目标的角度 + // 朝目标发射 Vector3 targetWorldPos = targetHitPos.position; Vector2 dir = ((Vector2)targetWorldPos - startPos).normalized; float targetAngle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f; - - string bulletId = i < bullitIDs.Count ? bullitIDs[i] : bullitIDs[0]; CreateBullet(sit, startPos, targetAngle, isDouble, true, bulletId, targetMonster, targetHitPos); } + else + { + // 目标不足或失效 → 按默认角度发射(不锁定) + CreateBullet(sit, startPos, defaultAngles[i], isDouble, isLock, bulletId); + } } } else if (isSanShe) @@ -1603,9 +1615,10 @@ public class GameMainPanel_FishBase : GameMainPanel_Base if (CreateFishManager.Instance == null) return result; - // ① 主锁目标排第一(打哪锁哪) + // ① 主锁目标排第一(打哪锁哪)—— 必须也满足路径可锁定,否则三发列表会被它污染 if (currSitData.isLock && currSitData.monCotl_Lock != null && - currSitData.monCotl_Lock.gameObject.activeInHierarchy) + currSitData.monCotl_Lock.gameObject.activeInHierarchy && + IsFishPathLockable(currSitData.monCotl_Lock)) { Transform pos = currSitData.monCotl_Lock_Position != null && currSitData.monCotl_Lock_Position.gameObject.activeInHierarchy ? currSitData.monCotl_Lock_Position @@ -1616,12 +1629,15 @@ public class GameMainPanel_FishBase : GameMainPanel_Base } // ② 按优先级从分类字典补满剩余位置 + // ⭐ 修复:之前漏了 fishDatas_hashCodekey_Small(普通鱼), + // 导致场上只有普通鱼时三发只找到1个目标 var dicts = new Dictionary[] { CreateFishManager.Instance.fishDatas_hashCodekey_TS_Boss, CreateFishManager.Instance.fishDatas_hashCodekey_Boss, CreateFishManager.Instance.fishDatas_hashCodekey_TS, CreateFishManager.Instance.fishDatas_hashCodekey_HJ, + CreateFishManager.Instance.fishDatas_hashCodekey_Small, }; foreach (var dict in dicts) @@ -1745,12 +1761,16 @@ public class GameMainPanel_FishBase : GameMainPanel_Base UpdateSingleLockFX(sit, sit.monCotl_Lock, sit.monCotl_Lock_Position, sit.lockFX); // 更新三发锁定额外图标 - for (int i = 0; i < sit.lockFX_Triple.Count && i < sit.tripleLockTargets.Count; i++) + // ⭐ tripleLockTargets[0] 是主目标(已在主 lockFX 显示), + // lockFX_Triple[0] 应对应 tripleLockTargets[1],以此类推 + for (int i = 0; i < sit.lockFX_Triple.Count; i++) { + int targetIdx = i + 1; // 跳过索引0(主目标) + if (targetIdx >= sit.tripleLockTargets.Count) break; var icon = sit.lockFX_Triple[i]; - var monster = sit.tripleLockTargets[i]; - var hitPos = sit.tripleLockPositions[i]; - if (icon == null || monster == null || hitPos == null) continue; + var monster = sit.tripleLockTargets[targetIdx]; + var hitPos = sit.tripleLockPositions[targetIdx]; + if (icon == null || monster == null) continue; UpdateSingleLockFX(sit, monster, hitPos, icon); } } @@ -1787,8 +1807,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base var monster = currSitData.monCotl_Lock; - // 目标无效:被对象池回收 / 不激活 / 被销毁 - if (monster == null || !monster.gameObject.activeInHierarchy) + // ⭐ 目标无效判定:被回收/销毁 OR 路径离场(progress > 0.8) + // 离场的鱼仍 active,但不应该继续锁定 + bool mainInvalid = monster == null + || !monster.gameObject.activeInHierarchy + || !IsFishPathLockable(monster); + + if (mainInvalid) { currSitData.ClearLock(); // 清除锁定 SyncTurretState(TurretState.Idle); @@ -1797,6 +1822,29 @@ public class GameMainPanel_FishBase : GameMainPanel_Base // ⭐⭐⭐ 关键:怪死了 → 动画回到 Idle ⭐⭐⭐ currSitData.ChangeState(TurretState.Idle); SyncTurretState(TurretState.Idle); + return; + } + + // ⭐ 检查三发锁定目标:移除已死亡或已离场的额外目标 + if (currSitData.tripleLockTargets.Count > 0) + { + bool changed = false; + for (int i = currSitData.tripleLockTargets.Count - 1; i >= 1; i--) + { + var t = currSitData.tripleLockTargets[i]; + // 失效判定:被回收/销毁 OR 路径离场 + if (t == null || !t.gameObject.activeInHierarchy || !IsFishPathLockable(t)) + { + currSitData.tripleLockTargets.RemoveAt(i); + currSitData.tripleLockPositions.RemoveAt(i); + changed = true; + } + } + // 有目标失效 → 清空三发列表,让 RefreshTripleLockIcons 重新找满3个 + if (changed) + { + currSitData.HideTripleLockIcons(); + } } } @@ -1812,10 +1860,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base // 激活后,当锁定的鱼死亡,自动转换到下一个目标 if (!_autoLockActivated) return; - // 已经有锁定目标并且还活着,就不重复找 + // 已经有锁定目标并且还活着且未离场,就不重复找 if (currSitData.isLock && currSitData.monCotl_Lock != null && - currSitData.monCotl_Lock.gameObject.activeInHierarchy) + currSitData.monCotl_Lock.gameObject.activeInHierarchy && + IsFishPathLockable(currSitData.monCotl_Lock)) { return; }