Files
zeling_v2/Assets/_Game/Scripts/Combat/LethalTrap.cs
Joywayer bedb0f8ff4 fix(combat): 地刺死亡判定改从 HurtBox 向上查找——死亡不再误传回检查点
此前经 other.transform.root 查 IDamageable,玩家被临时挂到其他
父物体(如移动平台)下时 root 非玩家根节点而漏判死亡,导致致死
触碰仍 Raise EVT_CheckpointRespawn 与死亡流程撞车。改为
other.GetComponentInParent 从 HurtBox 自身向上查找,任何层级
结构下死亡均只走死亡流程,存活才回溯检查点。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 11:20:10 +08:00

132 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseGames.Core;
using BaseGames.Core.Events;
using UnityEngine;
namespace BaseGames.Combat
{
/// <summary>
/// 致命陷阱(地刺、深渊等)——触碰即造成伤害、可无视无敌帧的固定危险区域:
///
/// ① 玩家 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下劈时玩家仍受地刺伤害。
/// </summary>
[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;
/// <summary>
/// 单次接触闩锁:防止同一次触碰内重复结算(如淡出等待期间的物理回调)。
/// 玩家 HurtBox 离开触发区OnTriggerExit2D含检查点传送移位后重置
/// 使陷阱对下一次触碰再次生效;死亡路径则经场景重载由 OnEnable 重置。
/// </summary>
private bool _triggered;
private void Awake()
{
var col = GetComponent<Collider2D>();
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<HurtBox>();
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 检查点回溯;
// 若存活,需由本组件 Raise 使其回到检查点。
// 从 HurtBox 自身向上查找(而非 transform.root玩家被临时挂到
// 其他父物体(如移动平台)下时 root 不是玩家根节点,会漏判死亡。
var damageable = other.GetComponentInParent<IDamageable>();
playerDiedFromDamage = damageable != null && !damageable.IsAlive;
}
}
// ── 2. 若玩家存活(或无 HurtBox / damage=0回溯至最近检查点 ────────────
if (!playerDiedFromDamage)
{
var cp = ServiceLocator.GetOrDefault<ICheckpointService>();
if (cp != null && cp.HasCheckpoint)
_onCheckpointRespawn?.Raise();
else
_onPlayerDied?.Raise();
}
}
private void OnTriggerExit2D(Collider2D other)
{
if ((_playerLayers.value & (1 << other.gameObject.layer)) == 0) return;
_triggered = false;
}
#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
}
}