using BaseGames.Core.Events; using UnityEngine; namespace BaseGames.World { /// /// 区域到达触发器(架构 22_QuestChallengeModule §3 扩展)。 /// 挂在场景中的 2D 触发碰撞体上,玩家进入时广播 EVT_AreaReached 事件, /// 驱动 ReachAreaObjective(markerTag 模式)的任务目标进度。 /// /// 使用方式: /// 1. 在目标区域创建空 GameObject,添加 Collider2D(勾选 IsTrigger)。 /// 2. 挂上 TriggerZone,填写 markerTag(与 ReachAreaObjective.markerTag 保持一致)。 /// 3. 将 EVT_AreaReached 事件频道资产拖入 _onAreaReached 字段。 /// 4. 将 QuestManager 同一 _onAreaReached 频道字段也引用同一资产即可联通。 /// [RequireComponent(typeof(Collider2D))] public class TriggerZone : MonoBehaviour { [Header("区域标识")] [Tooltip("区域唯一标记(如 \"ZONE_ForestEntry\")。需与 ReachAreaObjective.markerTag 保持完全一致。")] [SerializeField] private string _markerTag; [Tooltip("触发后是否只生效一次(推荐勾选,防止重复广播)。")] [SerializeField] private bool _triggerOnce = true; [Header("玩家层级")] [Tooltip("玩家所在的物理层,用于过滤非玩家碰撞体进入。只有属于此层的碰撞体才触发广播。")] [SerializeField] private LayerMask _playerLayer; [Header("事件频道")] [Tooltip("EVT_AreaReached 事件频道(StringEventChannelSO)。触发时以 markerTag 为 payload 广播。\n" + "需与 QuestManager._onAreaReached 字段引用同一资产。")] [SerializeField] private StringEventChannelSO _onAreaReached; private bool _triggered; /// 区域唯一标记(只读)。供编辑器工具(QuestModule 批量验证)交叉比对使用。 public string MarkerTag => _markerTag; private void OnTriggerEnter2D(Collider2D other) { if (_triggered) return; if (string.IsNullOrEmpty(_markerTag)) return; if (((1 << other.gameObject.layer) & _playerLayer.value) == 0) return; _onAreaReached?.Raise(_markerTag); if (_triggerOnce) _triggered = true; } /// 重置触发状态(如读档/重新进入关卡时调用)。 public void ResetTrigger() => _triggered = false; #if UNITY_EDITOR private void OnDrawGizmos() { if (string.IsNullOrEmpty(_markerTag)) return; Gizmos.color = new Color(0.2f, 0.8f, 0.4f, 0.25f); var col = GetComponent(); if (col != null) Gizmos.DrawWireSphere(col.bounds.center, 0.3f); } private void OnDrawGizmosSelected() { var col = GetComponent(); if (col == null) return; Gizmos.color = new Color(0.2f, 0.9f, 0.4f, 0.5f); Gizmos.DrawWireCube(col.bounds.center, col.bounds.size); UnityEditor.Handles.Label( col.bounds.center + Vector3.up * (col.bounds.extents.y + 0.2f), string.IsNullOrEmpty(_markerTag) ? "(未设置 markerTag)" : _markerTag); } #endif } }