chore: initial commit
This commit is contained in:
106
Assets/Scripts/Combat/HurtBox.cs
Normal file
106
Assets/Scripts/Combat/HurtBox.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using UnityEngine;
|
||||
using BaseGames.Parry;
|
||||
|
||||
namespace BaseGames.Combat
|
||||
{
|
||||
/// <summary>
|
||||
/// 受击盒组件。实现完整 8 步伤害流水线(架构 06_CombatModule §5)。
|
||||
/// 挂载在角色根节点或指定子节点上,Collider2D 需设 IsTrigger = true,
|
||||
/// Layer = PlayerHurtBox 或 EnemyHurtBox。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
public class HurtBox : MonoBehaviour
|
||||
{
|
||||
// ── 伤害接受方(Awake 注入)──────────────────────────────────────────
|
||||
private IDamageable _owner;
|
||||
private IShieldable _shieldable; // 由 PlayerController.Awake() 注入
|
||||
private ParrySystem _parrySystem; // Phase 2 由 PlayerController.Awake() 注入
|
||||
private IPoiseSource _poiseSource; // Phase 2 由 EnemyBase.Awake() 注入
|
||||
|
||||
private bool _isHurtBoxInvincible;
|
||||
private bool _isActive = true;
|
||||
|
||||
// ── 事件频道 ──────────────────────────────────────────────────────────
|
||||
[SerializeField] private DamageInfoEventChannelSO _onDamageDealt;
|
||||
[SerializeField] private HitConfirmedEventChannelSO _onHitConfirmed;
|
||||
|
||||
// ── 注入接口 ──────────────────────────────────────────────────────────
|
||||
public void SetShieldable(IShieldable shieldable) => _shieldable = shieldable;
|
||||
public void SetParrySystem(ParrySystem ps) => _parrySystem = ps;
|
||||
public void SetPoiseSource(IPoiseSource src) => _poiseSource = src;
|
||||
public void SetInvincible(bool value) => _isHurtBoxInvincible = value;
|
||||
public void SetActive(bool value) => _isActive = value;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_owner = GetComponentInParent<IDamageable>();
|
||||
if (_owner == null)
|
||||
Debug.LogWarning($"[HurtBox] {name}: 父节点中未找到 IDamageable 实现。", this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接受伤害(由 HitBox.OnTriggerEnter2D 直接调用)。
|
||||
/// ⚠️ 方法名必须为 ReceiveDamage。
|
||||
/// </summary>
|
||||
public void ReceiveDamage(DamageInfo info)
|
||||
{
|
||||
if (!_isActive || _owner == null) return;
|
||||
|
||||
// 1. 无敌帧检查
|
||||
if ((_owner.IsInvincible || _isHurtBoxInvincible)
|
||||
&& !info.Flags.HasFlag(DamageFlags.IgnoreIFrame)) return;
|
||||
|
||||
// 2. 弹反检查(Phase 1 _parrySystem == null 跳过)
|
||||
// ParrySystem 只暴露窗口状态,伤害数据留在 Combat 层,无跨程序集数据依赖。
|
||||
if (_parrySystem != null && info.Flags.HasFlag(DamageFlags.CanBeParried))
|
||||
if (_parrySystem.ConsumeParry()) return;
|
||||
|
||||
// 3. 霸体检查(Phase 1 _poiseSource == null 跳过)
|
||||
if (!info.Flags.HasFlag(DamageFlags.ForceBreak) && _poiseSource != null)
|
||||
{
|
||||
PoiseLevel curPoise = _poiseSource.GetCurrentPoiseLevel();
|
||||
if (curPoise == PoiseLevel.Unbreakable) return;
|
||||
if ((int)info.Break < (int)curPoise)
|
||||
{
|
||||
_onHitConfirmed?.Raise(new HitInfo
|
||||
{
|
||||
DamageInfo = info,
|
||||
HitPoint = transform.position,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 护盾层拦截(玩家专属,在防御减免前)
|
||||
if (_shieldable != null && _shieldable.HasShield)
|
||||
{
|
||||
int passThrough = _shieldable.AbsorbDamage(info.Amount);
|
||||
if (passThrough <= 0) return;
|
||||
info.Amount = passThrough;
|
||||
}
|
||||
|
||||
// 5. 计算 FinalDamage(防御减免,最低 1)
|
||||
int finalDamage = UnityEngine.Mathf.Max(1, info.Amount - _owner.Defense);
|
||||
info.Amount = finalDamage;
|
||||
info.FinalDamage = finalDamage;
|
||||
|
||||
// 6. 调用 _owner.TakeDamage
|
||||
_owner.TakeDamage(info);
|
||||
|
||||
// 7. 全局广播
|
||||
_onDamageDealt?.Raise(info);
|
||||
_onHitConfirmed?.Raise(new HitInfo
|
||||
{
|
||||
DamageInfo = info,
|
||||
HitPoint = transform.position,
|
||||
});
|
||||
|
||||
// 8. 状态效果触发(DoT — Fire / Poison)
|
||||
// 使用接口避免对 StatusEffects 程序集的直接依赖
|
||||
if (_owner is UnityEngine.MonoBehaviour mb)
|
||||
{
|
||||
mb.GetComponent<IStatusEffectable>()?.ApplyStatusEffect(info.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user