Files
zeling_v2/Assets/_Game/Scripts/Combat/LethalTrap.cs
2026-05-19 11:50:21 +08:00

118 lines
5.2 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;
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 使其回到检查点。
var damageable = other.transform.root.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();
}
}
#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
}
}