106 lines
4.6 KiB
C#
106 lines
4.6 KiB
C#
using BaseGames.Core.Events;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.Combat
|
||
{
|
||
/// <summary>
|
||
/// 致命陷阱(地刺、深渊等)——触碰即造成伤害、可无视无敌帧的固定危险区域:
|
||
///
|
||
/// ① 玩家 HurtBox 触碰时,通过 HurtBox.ReceiveDamage() 造成一次伤害
|
||
/// 并携带 IgnoreIFrame 标记(无视翻滚/受击无敌帧,保证陷阱的绝对威胁性)。
|
||
/// ② 若伤害导致玩家死亡 → PlayerController.TakeDamage 已 Raise EVT_PlayerDied,
|
||
/// 走完整死亡流程(死亡动画 → 重载场景)。
|
||
/// ③ 若玩家存活 → 本组件 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 — 触发后由 DeathRespawnService 接管回到检查点")]
|
||
[SerializeField] private VoidEventChannelSO _onPlayerDied;
|
||
|
||
[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)
|
||
_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
|
||
}
|
||
}
|