using System.Collections; using System.Collections.Generic; using UnityEngine; /// /// ⭐ 潜行Boss:ActivateBoss() 触发前处于"系统不存在"状态,三重隔离—— /// ① 不入鱼列表:CreateFishManager.OnlyFish 跳过 RegisterFishInstance(DeferFishRegister=true), /// 自动锁定枚举/技能选鱼/服务端击杀通知全部找不到此Boss /// ② 不可被打中:出场即禁用自身及全部子物体的 Collider2D /// (子弹 BullitMove 命中走 Collider 触碰 tag=Fish,物理层关闭后子弹直接穿过) /// ③ 不可被锁定:isLockable=false 双保险(不入字典本来也枚举不到) /// 由外部(动画事件/入场演出结束回调/流程代码)调用 ActivateBoss() 后恢复正常: /// 注册入鱼列表 + 恢复碰撞 + 允许锁定。 /// 潜行期走完路线 → 静默回池(不走 Id_DieFish_NotFX:不在字典只会打 NOT_FOUND 日志且不回收,会变野鱼)。 /// ⭐ 注意:潜行期不在鱼列表,新进房玩家的活鱼同步/全屏技能/冰冻均不包含此Boss,属预期行为; /// 激活后才正常参与所有系统。 /// public class StealthBossControl : DefaultBossControl { [Header("⭐ 潜行模式(激活前不入鱼列表/不可被打/不可被锁)")] [Tooltip("true=出场后等待 ActivateBoss() 激活后才入列表/可被打/可被锁;false=行为与 DefaultBossControl 完全一致")] public bool stealthUntilActivated = true; /// 是否已激活(已补注册+已恢复碰撞)。OnEnable 重置供池复用。 private bool _activated; /// 潜行期禁用的碰撞器缓存(激活时恢复) private Collider2D[] _stealthCols; /// 各碰撞器出厂时的 enabled 状态(恢复时只恢复原本就启用的,出厂禁用的不动) private bool[] _stealthColWasEnabled; /// /// ⭐ 指定激活方法:调用后 Boss 进入战斗状态—— /// 补注册入鱼列表(OnlyFish 同款入口,含 guid 冲突处理与创建日志)+ 恢复碰撞 + 允许锁定。 /// 由动画事件/演出回调/流程代码在合适的时机调用。重复调用安全; /// stealthUntilActivated=false 时调用无任何副作用。 /// public void ActivateBoss() { if (_activated) return; _activated = true; // ⓪ 解除"系统不存在"标记(isDead 兼作潜行标记,见 OnEnable 处注释) isDead = false; // ① 补注册入鱼列表(fishenum 在 OnlyFish/OnEnable 已赋值,与立即注册的鱼同源同值) CreateFishManager.Instance.RegisterFishInstance(this, (int)fishenum); // ② 恢复潜行期禁用的碰撞器(只恢复出厂就 enabled 的) if (_stealthCols != null) { for (int i = 0; i < _stealthCols.Length; i++) { if (_stealthCols[i] != null && _stealthColWasEnabled[i]) _stealthCols[i].enabled = true; } _stealthCols = null; _stealthColWasEnabled = null; } // ③ 允许锁定(触发 OnLockable 事件,GameMainPanel 自动锁定可订阅) NotifyLockable(); } public override void OnEnable() { base.OnEnable(); // ⭐ 池复用重置:每次出场重新进入潜行期,等外部再次 ActivateBoss() _activated = false; _stealthCols = null; _stealthColWasEnabled = null; if (!stealthUntilActivated) return; // 潜行期:禁用自身及全部子物体碰撞器(true=含未激活的,出场特效的碰撞也一并关闭) _stealthCols = GetComponentsInChildren(true); _stealthColWasEnabled = new bool[_stealthCols.Length]; for (int i = 0; i < _stealthCols.Length; i++) { _stealthColWasEnabled[i] = _stealthCols[i] != null && _stealthCols[i].enabled; if (_stealthCols[i] != null) _stealthCols[i].enabled = false; } // 锁定双保险(base.OnEnable 里 isLockable=!needLockEvent 可能已置 true,这里显式关掉) isLockable = false; // ⭐ 状态层兜底(拦手动锁定的关键):isDead=true 复用"死亡鱼不可打不可锁"的既定检查—— // - 手动锁定 HandleLock 不查字典/isLockable,只查 isDead → 这里必须置 true 才拦得住; // - 子弹命中三处入口(BullitMove 碰撞/触发/AttackFish)同样只查 isDead → 潜行期子弹穿过; // - 即使模型切换/特效在运行时动态激活了新的 Collider2D(不在 _stealthCols 缓存内), // 状态层依然拦截,双保险不依赖碰撞器禁用是否完整。 // 激活时在 ActivateBoss ⓪ 复位为 false,池复用时 OnEnable 也复位(base.OnEnable) isDead = true; } public override void OnMoveUpdata() { // ⭐ 潜行期走完路线:静默回池—— // 不在鱼列表,Id_DieFish_NotFX(guid) 只会打 NOT_FOUND 日志且不回收 → 变野鱼, // 所以这里直接回池(isMove=false 防下一帧再进,Pool.Return 触发 OnDisable 复位) if (stealthUntilActivated && !_activated && moveTime >= monsterData.moveLine.moveTime) { isMove = false; Pool.Instance.Return(gameObject); return; } base.OnMoveUpdata(); } }