From c91eaef60bae152d9202521cf4e2004af80d703f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A3=AE2003?= <2384017988@qq.com> Date: Tue, 29 Sep 2026 00:45:16 +0800 Subject: [PATCH] 1 --- Assets/MyGame/Scripts/Turret/SitPosData.cs | 218 +++++++++++++----- .../aa/Game/FLZY/BOSS/JL/fish_136.prefab | 2 +- .../aa/UI/Game/GameMainPanel_FishBase.cs | 82 +++++-- 3 files changed, 226 insertions(+), 76 deletions(-) diff --git a/Assets/MyGame/Scripts/Turret/SitPosData.cs b/Assets/MyGame/Scripts/Turret/SitPosData.cs index d903370e2..4b7bebdbe 100644 --- a/Assets/MyGame/Scripts/Turret/SitPosData.cs +++ b/Assets/MyGame/Scripts/Turret/SitPosData.cs @@ -218,6 +218,16 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler public List lockFX_Triple = new List(); // 三发锁定额外2个图标 public List tripleLockTargets = new List(); public List tripleLockPositions = new List(); + /// + /// ⭐ 三发锁位是否处于"空置等手动点击"状态(索引与 tripleLockTargets 对齐)。 + /// true = 该锁位打死后自动检测没找到鱼 → 保持空着,不再自动补位,必须玩家手动点击才锁。 + /// + private readonly List tripleSlotIdle = new List(); + /// + /// ⭐ 该锁位是否由玩家手动点选(索引与 tripleLockTargets 对齐)。 + /// true = 玩家自己点的鱼 → 离场前一直跟,死了才换;手动身份会跟着鱼一起移入子锁位。 + /// + private readonly List tripleSlotManual = new List(); // ------------------------- // UI @@ -2021,37 +2031,23 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler // 确保 lockFX_Triple 有2个克隆的图标(+主图标=3个) EnsureTripleLockIcons(); + // ⭐ 固定3个锁位(不足的留空占位,下一帧由锁定系统自动尝试补一次) + EnsureTripleLockSlots(3); - tripleLockTargets.Clear(); - tripleLockPositions.Clear(); - - // 第一个目标用主 lockFX - var primary = targets[0]; - monCotl_Lock = primary.monster; - monCotl_Lock_Position = primary.hitPos; - isLock = true; - lockFX.SetActive(true); - tripleLockTargets.Add(primary.monster); - tripleLockPositions.Add(primary.hitPos); - - // 第二个和第三个目标用 lockFX_Triple - for (int i = 1; i < targets.Count && i < 3; i++) + for (int i = 0; i < 3; i++) { - int idx = i - 1; - if (idx < lockFX_Triple.Count && lockFX_Triple[idx] != null) - { - lockFX_Triple[idx].SetActive(true); - tripleLockTargets.Add(targets[i].monster); - tripleLockPositions.Add(targets[i].hitPos); - } + bool has = i < targets.Count; + tripleLockTargets[i] = has ? targets[i].monster : null; + tripleLockPositions[i] = has ? targets[i].hitPos : null; + // ⭐ 自动建位:允许自动补位(补不到会转成"空置等手动点击"),不算玩家手动 + tripleSlotIdle[i] = false; + tripleSlotManual[i] = false; } - // 隐藏多余的 - for (int i = targets.Count - 1; i < lockFX_Triple.Count; i++) - { - if (lockFX_Triple[i] != null) - lockFX_Triple[i].SetActive(false); - } + monCotl_Lock = targets[0].monster; + monCotl_Lock_Position = targets[0].hitPos; + isLock = targets[0].monster != null; + RefreshTripleIconVisibility(); } private void EnsureTripleLockIcons() @@ -2065,6 +2061,18 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler } } + /// 把锁位列表补齐到 count 个(用 null 占位,保证三个列表索引对齐) + public void EnsureTripleLockSlots(int count) + { + while (tripleLockTargets.Count < count) + { + tripleLockTargets.Add(null); + tripleLockPositions.Add(null); + tripleSlotIdle.Add(false); + tripleSlotManual.Add(false); + } + } + public void HideTripleLockIcons() { foreach (var icon in lockFX_Triple) @@ -2074,69 +2082,163 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler } tripleLockTargets.Clear(); tripleLockPositions.Clear(); + tripleSlotIdle.Clear(); + tripleSlotManual.Clear(); } // ==================== 三发锁位(每个锁位独立维护) ==================== // ⭐ index=0 是主锁位(monCotl_Lock + 主 lockFX),1..2 对应 lockFX_Triple[index-1] - /// 取 index(1..2) 对应的额外锁定图标 - private GameObject GetTripleIcon(int index) + /// 按每个锁位是否有鱼刷新3个锁定圈显示(有目标才有圈) + private void RefreshTripleIconVisibility() { - int iconIdx = index - 1; - if (lockFX_Triple == null || iconIdx < 0 || iconIdx >= lockFX_Triple.Count) return null; - return lockFX_Triple[iconIdx]; + if (lockFX != null) + lockFX.SetActive(tripleLockTargets.Count > 0 && tripleLockTargets[0] != null); + + for (int i = 0; i < lockFX_Triple.Count; i++) + { + if (lockFX_Triple[i] == null) continue; + int slot = i + 1; + lockFX_Triple[i].SetActive(slot < tripleLockTargets.Count && tripleLockTargets[slot] != null); + } } - /// 替换单个三发锁位(锁位独立:某条鱼死了只补这一个锁位,其他锁位不动) + /// 替换单个三发锁位(自动补位用:锁位独立,只补这一个,其他锁位不动) public void SetTripleLockSlot(int index, MonsterContral monster, Transform hitPos) { if (index < 0) return; - while (tripleLockTargets.Count <= index) - { - tripleLockTargets.Add(null); - tripleLockPositions.Add(null); - } + EnsureTripleLockSlots(index + 1); tripleLockTargets[index] = monster; tripleLockPositions[index] = hitPos; + tripleSlotIdle[index] = false; + tripleSlotManual[index] = false; // 自动补的位不算玩家手动 if (index == 0) { monCotl_Lock = monster; monCotl_Lock_Position = hitPos; isLock = monster != null; - if (lockFX != null) lockFX.SetActive(isLock); - } - else - { - var icon = GetTripleIcon(index); - if (icon != null) icon.SetActive(monster != null); } + RefreshTripleIconVisibility(); } - /// 清空单个三发锁位(该锁位暂时没鱼可补):保留槽位占位,只隐藏该锁位图标 + /// + /// 清空单个三发锁位:该位打死后自动检测没找到鱼 → 保留占位、隐藏该位图标, + /// 并标记"空置等手动点击"(不再自动补位,必须玩家点击才锁)。 + /// public void ClearTripleLockSlot(int index) { if (index < 0 || index >= tripleLockTargets.Count) return; tripleLockTargets[index] = null; - if (index < tripleLockPositions.Count) tripleLockPositions[index] = null; + tripleLockPositions[index] = null; + tripleSlotIdle[index] = true; + tripleSlotManual[index] = false; if (index == 0) { monCotl_Lock = null; monCotl_Lock_Position = null; isLock = false; - if (lockFX != null) lockFX.SetActive(false); } - else + RefreshTripleIconVisibility(); + } + + /// 该锁位是否处于"空置等手动点击"状态(不再自动补位) + public bool IsTripleSlotIdle(int index) + { + return index >= 0 && index < tripleSlotIdle.Count && tripleSlotIdle[index]; + } + + /// + /// 该锁位是否是玩家手动点选的鱼(手动身份跟着鱼一起移入子锁位)。 + /// true → 离场前一直跟,只有鱼死了才换。 + /// + public bool IsTripleSlotManual(int index) + { + return index >= 0 && index < tripleSlotManual.Count && tripleSlotManual[index]; + } + + /// 三个锁位是否还有任意一个有效目标(鱼还活着) + public bool HasAnyTripleTarget + { + get { - var icon = GetTripleIcon(index); - if (icon != null) icon.SetActive(false); + foreach (var m in tripleLockTargets) + if (m != null && m.gameObject.activeInHierarchy) return true; + return false; } } + /// 当前三发锁位上有效的鱼 guid 列表(开火同步 monsterIDs 用) + public List GetTripleLockGuids() + { + var list = new List(); + foreach (var m in tripleLockTargets) + if (m != null && !m.isDead && m.gameObject.activeInHierarchy) + list.Add(m.guid); + return list; + } + + /// 该 guid 的鱼是否已经在某个三发锁位上 + public bool IsFishInTripleSlots(string guid) + { + if (string.IsNullOrEmpty(guid)) return false; + foreach (var m in tripleLockTargets) + if (m != null && m.guid == guid) return true; + return false; + } + + /// + /// ⭐ 手动点击锁鱼(战神+三发+锁定):新点的鱼占主锁位,原来锁位上的鱼依次排到子锁位, + /// 最多保留3个(超过时最旧的被挤掉)。 + /// 手动身份跟着鱼一起转移(移入子锁位后依然是手动锁定,离场前不会被自动换掉); + /// 挤位前会先"紧凑化",跳过空位/死鱼,避免有空位时误丢掉还活着的锁定目标。 + /// + public void PushTripleLockSlot(MonsterContral monster, Transform hitPos) + { + EnsureTripleLockIcons(); + + // ① 收集现有锁位上还活着的鱼(跳过空位和死鱼),按 新→旧 顺序,最多留2个 + var keepMon = new List(); + var keepPos = new List(); + var keepManual = new List(); + for (int i = 0; i < tripleLockTargets.Count && keepMon.Count < 2; i++) + { + var m = tripleLockTargets[i]; + if (m == null || !m.gameObject.activeInHierarchy) continue; + if (m == monster) continue; // 同一条鱼不重复占位 + keepMon.Add(m); + keepPos.Add(i < tripleLockPositions.Count ? tripleLockPositions[i] : null); + keepManual.Add(i < tripleSlotManual.Count && tripleSlotManual[i]); + } + + // ② 新点的鱼占主锁位,其余依次排到子锁位 + EnsureTripleLockSlots(3); + tripleLockTargets[0] = monster; + tripleLockPositions[0] = hitPos; + tripleSlotIdle[0] = false; + tripleSlotManual[0] = true; // 玩家手动点的 + + for (int i = 1; i < 3; i++) + { + int k = i - 1; + bool has = k < keepMon.Count; + tripleLockTargets[i] = has ? keepMon[k] : null; + tripleLockPositions[i] = has ? keepPos[k] : null; + // ⭐ 空位标记"等手动点击":玩家在自己点选,空位不再自动补 + tripleSlotIdle[i] = !has; + tripleSlotManual[i] = has && keepManual[k]; + } + + monCotl_Lock = monster; + monCotl_Lock_Position = hitPos; + isLock = true; + RefreshTripleIconVisibility(); + } + /// /// 主锁位空缺时,把其他存活的锁位提升为主锁,避免主锁死掉导致整个三发模式中断。 - /// 提升后原锁位留空,下一帧会自动补新目标。成功返回 true。 + /// 提升后原锁位留空并允许自动补一次。成功返回 true。 /// public bool PromoteTripleLockSlotToMain() { @@ -2150,13 +2252,21 @@ public class SitPosData : MonoBehaviour, IPointerDownHandler, IPointerUpHandler tripleLockPositions[0] = pos; tripleLockTargets[i] = null; tripleLockPositions[i] = null; - var icon = GetTripleIcon(i); - if (icon != null) icon.SetActive(false); + if (i < tripleSlotIdle.Count) + { + tripleSlotIdle[0] = tripleSlotIdle[i]; + tripleSlotIdle[i] = false; // 让出的位置允许自动补一次 + } + if (i < tripleSlotManual.Count) + { + tripleSlotManual[0] = tripleSlotManual[i]; // 手动身份跟着鱼提升 + tripleSlotManual[i] = false; + } monCotl_Lock = mon; monCotl_Lock_Position = pos; isLock = true; - if (lockFX != null) lockFX.SetActive(true); + RefreshTripleIconVisibility(); return true; } return false; diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/JL/fish_136.prefab b/Assets/MyGame/aa/Game/FLZY/BOSS/JL/fish_136.prefab index 6040967b5..70d084b47 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/JL/fish_136.prefab +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/JL/fish_136.prefab @@ -930,7 +930,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 1361653457580592, guid: 055ba0a273a3d0c48a43f4fb3f92dc4d, type: 3} propertyPath: m_IsActive - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 1361653457580592, guid: 055ba0a273a3d0c48a43f4fb3f92dc4d, type: 3} propertyPath: m_TagString diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index e0101c8f3..28da0f206 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -3565,6 +3565,21 @@ public class GameMainPanel_FishBase : GameMainPanel_Base Transform lockTr = ResolveLockTransform(monster, out colliderIndex, true); // ⭐ lockPoint 和 colliderList 全部未激活 → 不锁定这条鱼 if (lockTr == null) return; + + // ⭐⭐⭐ 战神 + 三发 + 锁定(散射三个锁定圈):手动点击 = 占主锁位, + // 原来的主锁位自动挤到子锁位,子锁位依次后移,最多锁3个 + if (IsZhanShenTripleMode()) + { + // 已经在锁位上的鱼 → 不重复加 + if (currSitData.IsFishInTripleSlots(monster.guid)) return; + + currSitData.PushTripleLockSlot(monster, lockTr); + currSitData.isManualLock = true; + _autoLockActivated = true; + SyncLock(currSitData.GetTripleLockGuids(), colliderIndex); + return; + } + // ⭐ 标记为手动锁定:不受路径进度(0.1~0.9)限制,鱼离场前一直锁定 currSitData.isManualLock = true; currSitData.SetLockTarget(monster, lockTr); @@ -3573,6 +3588,15 @@ public class GameMainPanel_FishBase : GameMainPanel_Base // ⭐ 手动锁定成功 → 激活自动锁定(该鱼死亡后自动转换目标) _autoLockActivated = true; } + + /// 是否处于 战神 + 三发 + 锁定 模式(散射激光 + 3个锁定圈) + private bool IsZhanShenTripleMode() + { + return currSitData != null + && currSitData.currentZhanShenData != null + && toggle_Three != null && toggle_Three.isOn + && toggle_Lock != null && toggle_Lock.isOn; + } private void UpdateLockFX() { @@ -3650,36 +3674,42 @@ public class GameMainPanel_FishBase : GameMainPanel_Base } private void CheckLockTargetValid() { - // ⭐⭐⭐ 三发模式:每个锁位独立维护 —— 鱼死了 或 路径离场时,只补那一个锁位,其他锁位不动 + // ⭐⭐⭐ 三发模式:每个锁位独立维护 —— 鱼死了/路径离场时只补那一个锁位,其他锁位不动。 + // 补位只尝试一次:补到了就锁上;补不到该锁位转"空置等手动点击"(不再自动补)。 // (Count 由 SetTripleLockTargets 建立;HideTripleLockIcons 才清成 0) if (currSitData.tripleLockTargets.Count > 0) { - // ⭐ 补齐到3个锁位(三发=最多3个目标):某位暂时没鱼可补就留空占位,下一帧继续尝试 - while (currSitData.tripleLockTargets.Count < 3) - { - currSitData.tripleLockTargets.Add(null); - currSitData.tripleLockPositions.Add(null); - } + // ⭐ 固定3个锁位(三发=最多3个目标) + currSitData.EnsureTripleLockSlots(3); for (int i = currSitData.tripleLockTargets.Count - 1; i >= 0; i--) { var t = currSitData.tripleLockTargets[i]; - // ⭐ 鱼死了(被回收/销毁) → 补这一个锁位 - if (t == null || !t.gameObject.activeInHierarchy) + // ---- 该锁位有鱼:判断是否需要更换 ---- + if (t != null && t.gameObject.activeInHierarchy) { - RefillTripleLockSlot(i); + // ⭐ 玩家手动点选的锁位 → 离场前一直跟,死了才换。 + // 手动身份是跟着鱼走的:被挤到子锁位后依然是手动,不会被自动换掉 + if (currSitData.IsTripleSlotManual(i)) continue; + + // ⭐ 路径离场(超出 0.1~0.9) 或 被 SuoDing 取消勾选 → 只补这一个锁位 + if (!IsFishPathLockable(t) || !IsFishAllowedBySuoDing(t)) + RefillTripleLockSlot(i); continue; } - // ⭐ 主锁位是玩家手动锁的 → 离场前一直跟,不自动更换 - if (i == 0 && currSitData.isManualLock) continue; + // ---- 该锁位空着 ---- + // ⭐ "空置等手动点击"状态 → 不再自动补位,必须玩家点击才锁 + if (currSitData.IsTripleSlotIdle(i)) continue; - // ⭐ 自动锁定的锁位:路径离场(超出 0.1~0.9) 或 被 SuoDing 取消勾选 - // → 只补这一个锁位,其他锁位不动 - if (!IsFishPathLockable(t) || !IsFishAllowedBySuoDing(t)) - RefillTripleLockSlot(i); + // ⭐ 刚打死后重新检测:只尝试这一次,成功就锁上,失败则转成"空置等手动" + RefillTripleLockSlot(i); } + + // ⭐ 三个锁位全空 → 暂时不锁定,等玩家手动点击才锁(关掉自动锁定激活标记) + if (!currSitData.HasAnyTripleTarget) + _autoLockActivated = false; return; } @@ -4220,13 +4250,23 @@ public class GameMainPanel_FishBase : GameMainPanel_Base auto = currSitData.IsAutoAttackOn }; - // ⭐ 战神 三发 + 锁定:查找 3 个优先级目标,写入 monsterIDs(FireLaser 分散打三个用) - // 正常炮台三合一打主锁目标(monCotl_Lock 已由 SyncLock/SyncBotLock 同步),不需要 monsterIDs + // ⭐ 战神 三发 + 锁定:3个锁定目标写入 monsterIDs(FireLaser 分散打三个用) + // ⭐ 优先用当前维护的3个锁位(玩家手动点选的目标) → 打哪锁哪 + // 锁位上没有有效目标时才按优先级现找。正常炮台三合一打主锁目标 + // (monCotl_Lock 已由 SyncLock/SyncBotLock 同步),不需要 monsterIDs if (isSanShe && isLock && currSitData.currentZhanShenData != null) { - var targets = FindFireTargets(3); - if (targets.Count > 0) - fireData.monsterIDs = targets.Select(t => t.monster.guid).ToList(); + var lockedGuids = currSitData.GetTripleLockGuids(); + if (lockedGuids.Count > 0) + { + fireData.monsterIDs = lockedGuids; + } + else + { + var targets = FindFireTargets(3); + if (targets.Count > 0) + fireData.monsterIDs = targets.Select(t => t.monster.guid).ToList(); + } } SyncGameData sgd = new SyncGameData