using UnityEngine; using BaseGames.AI; using BaseGames.Core.Events; namespace BaseGames.Enemies { /// /// Boss 开战触发:玩家进入竞技场触发区时,广播开战事件并让 Boss 的决策层从静置态进战。 /// 此前开战事件频道全项目零发送方,Boss 永远不会开战。 /// /// 放在 Boss 房间入口的触发区上(Collider2D + isTrigger)。只触发一次。 /// 漏配一律在 Awake 显式报错——静默不触发会表现为"Boss 站着不动",极难定位。 /// [RequireComponent(typeof(Collider2D))] public sealed class BossFightTrigger : MonoBehaviour { [Header("目标 Boss")] [Tooltip("要唤醒的 Boss 的决策层组件")] [SerializeField] private EnemyAiBrain _bossBrain; [Header("事件频道")] [Tooltip("EVT_BossFightStarted — payload 为 bossId,驱动全局状态机 / 后处理 / HUD")] [SerializeField] private StringEventChannelSO _onBossFightStarted; [Tooltip("EVT_BossFightEnded — 布尔开关频道,true 表示开始,驱动 Boss 血条与 BGM 切换")] [SerializeField] private BoolEventChannelSO _onBossFightToggled; [Header("标识")] [Tooltip("Boss id,与 Boss 身上配置的 bossId 一致")] [SerializeField] private string _bossId; [Header("触发条件")] [Tooltip("玩家所在的层")] [SerializeField] private LayerMask _playerLayers; private bool _fired; // 漏配处理沿用 EnemyAiBrain 的形态:逐条点名报错 + 停用组件。 // 不做「缺谁就跳过谁」的部分执行——半开的战斗(有 BGM 没血条、Boss 不动) // 比彻底不开更难查,问题必须停在配置这一层。 private void Awake() { bool valid = true; var col = GetComponent(); if (!col.isTrigger) { Debug.LogError($"[BossFightTrigger] {name} 的 Collider2D 未勾选 Is Trigger,无法触发开战。", this); valid = false; } if (_bossBrain == null) { Debug.LogError($"[BossFightTrigger] {name} 未指定目标 Boss 的 EnemyAiBrain,开战不会生效。", this); valid = false; } if (string.IsNullOrEmpty(_bossId)) { Debug.LogError($"[BossFightTrigger] {name} 未填 bossId,BGM / 血条无法定位该 Boss。", this); valid = false; } if (_onBossFightStarted == null) { Debug.LogError($"[BossFightTrigger] {name} 未绑定开战事件频道,全局状态机 / 后处理不会响应开战。", this); valid = false; } if (_onBossFightToggled == null) { Debug.LogError($"[BossFightTrigger] {name} 未绑定开战开关频道,Boss 血条与战斗 BGM 不会切换。", this); valid = false; } // 掩码为空 = 任何层都过不了下面的判定,触发区形同虚设。 if (_playerLayers.value == 0) { Debug.LogError($"[BossFightTrigger] {name} 的玩家层掩码为空,触发区永远不会被触发。", this); valid = false; } if (!valid) enabled = false; } // 能走到这里说明 Awake 的配置校验全过了,故不再判空—— // 判空只会把已经报过错的漏配再盖一层。 private void OnTriggerEnter2D(Collider2D other) { if (_fired) return; if ((_playerLayers.value & (1 << other.gameObject.layer)) == 0) return; _fired = true; _onBossFightStarted.Raise(_bossId); _onBossFightToggled.Raise(true); _bossBrain.Send(AiSignal.Engaged); } /// 供存档回载 / 重试时复位(Boss 未被击败则重新可触发)。 public void ResetTrigger() => _fired = false; } }