using BaseGames.Core; using BaseGames.Core.Events; using UnityEngine; namespace BaseGames.Combat { /// /// 致命陷阱(地刺、深渊等)——触碰即造成伤害、可无视无敌帧的固定危险区域: /// /// ① 玩家 HurtBox 触碰时,通过 HurtBox.ReceiveDamage() 造成一次伤害 /// 并携带 IgnoreIFrame 标记(无视翻滚/受击无敌帧,保证陷阱的绝对威胁性)。 /// ② 若伤害导致玩家死亡 → PlayerController.TakeDamage 已 Raise EVT_PlayerDied, /// 走完整死亡流程(死亡动画 → 重载场景)。 /// ③ 若玩家存活且场景内有检查点 → Raise EVT_CheckpointRespawn, /// 由 CheckpointRespawnHandler 执行淡出→传送→淡入,不重载场景。 /// ④ 若玩家存活但场景内无检查点 → Raise EVT_PlayerDied 作为兜底, /// 仍由 DeathRespawnService 重载场景回到存档点。 /// /// 可下劈(Pogo): /// - 将 _canPogo = true,并在地刺顶部添加子 GameObject: /// · 挂 HurtBox 组件(EnemyHurtBox 层) /// · 父链上无 IDamageable → ReceiveDamage 无副作用(HP 不扣除) /// · 玩家下劈 HitBox 命中该 HurtBox → HitBox.OnHitConfirmed → /// WeaponHitBoxInstance.OnDownHitConfirmed → DownAttackState.OnDownHitConfirmed /// → Move.Jump() 完成弹跳,无需额外代码。 /// - _canPogo = false 则不添加顶部 HurtBox,下劈时玩家仍受地刺伤害。 /// [RequireComponent(typeof(Collider2D))] public class LethalTrap : MonoBehaviour { [Header("伤害")] [Tooltip("每次触碰造成的伤害量(建议设为 1,确保任意陷阱触碰即扟一格血量)")] [SerializeField] private int _damage = 1; [Header("检测")] [Tooltip("勾选 PlayerHurtBox 层")] [SerializeField] private LayerMask _playerLayers; [Header("事件")] [Tooltip("EVT_PlayerDied — 玩家存活但场景内无检查点时触发,走完整死亡/重载流程")] [SerializeField] private VoidEventChannelSO _onPlayerDied; [Tooltip("EVT_CheckpointRespawn — 玩家存活且场景内有检查点时触发,执行原地传送")] [SerializeField] private VoidEventChannelSO _onCheckpointRespawn; [Header("设计")] [Tooltip("true = 顶部有 HurtBox 子节点可下劈弹跳(需手动添加 Pogo Surface 子节点)")] [SerializeField] private bool _canPogo = true; private bool _triggered; private void Awake() { var col = GetComponent(); if (!col.isTrigger) { col.isTrigger = true; Debug.LogWarning($"[LethalTrap] {name}: Collider2D.isTrigger 已自动设为 true。", this); } } private void OnEnable() => _triggered = false; private void OnTriggerEnter2D(Collider2D other) { if (_triggered) return; if ((_playerLayers.value & (1 << other.gameObject.layer)) == 0) return; _triggered = true; // ── 1. 通过 HurtBox 流水线造成伤害(含防御计算,携带 IgnoreIFrame)──────── bool playerDiedFromDamage = false; if (_damage > 0) { var hurtBox = other.GetComponent(); if (hurtBox != null) { var info = new DamageInfo.Builder() .SetRaw(_damage) .SetFlags(DamageFlags.IgnoreIFrame) // 无视无敌帧(翻滚/受击) .SetSourceId("lethal_trap") .Build(); hurtBox.ReceiveDamage(info); // 检测伤害后玩家存活状态: // 若已死亡,PlayerController.TakeDamage 已在同帧内 Raise EVT_PlayerDied; // 若存活,需由本组件 Raise 使其回到检查点。 var damageable = other.transform.root.GetComponentInParent(); playerDiedFromDamage = damageable != null && !damageable.IsAlive; } } // ── 2. 若玩家存活(或无 HurtBox / damage=0),回溯至最近检查点 ──────────── if (!playerDiedFromDamage) { var cp = ServiceLocator.GetOrDefault(); if (cp != null && cp.HasCheckpoint) _onCheckpointRespawn?.Raise(); else _onPlayerDied?.Raise(); } } #if UNITY_EDITOR [UnityEngine.ContextMenu("打印 Pogo 提示")] private void PrintPogoInfo() { Debug.Log( _canPogo ? $"[LethalTrap] {name}: _canPogo=true。请在顶部添加子 GO + HurtBox(EnemyHurtBox 层) + Collider2D(isTrigger=true),父链上无 IDamageable。" : $"[LethalTrap] {name}: _canPogo=false,无下劈弹跳。", this); } #endif } }