多轮审查和修复
This commit is contained in:
@@ -1,20 +1,137 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using BaseGames.Core.Events;
|
||||
|
||||
namespace BaseGames.Combat
|
||||
{
|
||||
/// <summary>
|
||||
/// 护盾组件(Phase 1 存根)。实现 IShieldable 接口供 HurtBox 注入。
|
||||
/// Phase 2 实现完整护盾逻辑(护盾值、再生、破盾事件)。
|
||||
/// 护盾组件。实现 IShieldable 接口供 HurtBox 注入。
|
||||
/// 护盾参数通过 ShieldConfigSO 集中配置。
|
||||
/// </summary>
|
||||
public class ShieldComponent : MonoBehaviour, IShieldable
|
||||
{
|
||||
public bool HasShield { get; private set; }
|
||||
[Header("配置资产")]
|
||||
[SerializeField] private ShieldConfigSO _config;
|
||||
|
||||
[Header("VFX 事件频道")]
|
||||
[SerializeField] private VoidEventChannelSO _onShieldBrokenChannel; // 护盾破碎 → 播放破碎 VFX
|
||||
[SerializeField] private VoidEventChannelSO _onShieldRestoredChannel; // 护盾恢复 → 播放恢复 VFX
|
||||
|
||||
// ── 运行时属性 ────────────────────────────────────────────────────────
|
||||
public int MaxShieldHP => _config.MaxShieldHP;
|
||||
public int CurrentShieldHP { get; private set; }
|
||||
/// <summary>当前是否能吸收伤害(护盾 HP > 0 且不在破碎惩罚期)。</summary>
|
||||
public bool HasShield => CurrentShieldHP > 0 && _brokenPenaltyTimer <= 0f;
|
||||
|
||||
private float AbsorptionRatio => _config.DamageAbsorptionRatio;
|
||||
private float RechargeDelay => _config.RechargeDelay;
|
||||
private float RechargeRate => _config.RechargeRate;
|
||||
private float BrokenPenaltyDur => _config.BrokenPenaltyDuration;
|
||||
private float ParryRestoreRatio => _config.ParryRestoreRatio;
|
||||
|
||||
public event Action<int, int> OnShieldChanged; // (current, max)
|
||||
public event Action OnShieldBroken;
|
||||
|
||||
private float _regenDelayTimer;
|
||||
private float _brokenPenaltyTimer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Debug.Assert(_config != null, "[ShieldComponent] _config 未赋值,请在 Inspector 中指定 ShieldConfigSO。", this);
|
||||
CurrentShieldHP = MaxShieldHP;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
int maxHP = MaxShieldHP;
|
||||
if (maxHP <= 0) return;
|
||||
|
||||
// 破碎惩罚计时
|
||||
if (_brokenPenaltyTimer > 0f)
|
||||
{
|
||||
_brokenPenaltyTimer -= Time.deltaTime;
|
||||
// 破碎惩罚结束 → 广播护盾恢复事件(VFX 钩子)
|
||||
if (_brokenPenaltyTimer <= 0f)
|
||||
_onShieldRestoredChannel?.Raise();
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentShieldHP >= maxHP) return;
|
||||
if (RechargeRate <= 0f) return;
|
||||
|
||||
if (_regenDelayTimer > 0f)
|
||||
{
|
||||
_regenDelayTimer -= Time.deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
int prev = CurrentShieldHP;
|
||||
CurrentShieldHP = Mathf.Min(CurrentShieldHP + Mathf.CeilToInt(RechargeRate * Time.deltaTime), maxHP);
|
||||
if (CurrentShieldHP != prev)
|
||||
OnShieldChanged?.Invoke(CurrentShieldHP, maxHP);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试以护盾吸收伤害。
|
||||
/// 返回穿透量(0 = 全部吸收,>0 = 穿透量继续走 TakeDamage 流程)。
|
||||
/// Phase 1:护盾不存在,全量穿透。
|
||||
/// 尝试以护盾吸收伤害。返回穿透量(0=全部吸收,>0=穿透量继续走 TakeDamage 流程)。
|
||||
/// </summary>
|
||||
public int AbsorbDamage(int amount) => amount;
|
||||
public int AbsorbDamage(int amount)
|
||||
{
|
||||
if (!HasShield) return amount;
|
||||
|
||||
_regenDelayTimer = RechargeDelay;
|
||||
|
||||
int maxHP = MaxShieldHP;
|
||||
// 按吸收比例计算实际由护盾承担的伤害
|
||||
int toAbsorb = Mathf.FloorToInt(amount * AbsorptionRatio);
|
||||
toAbsorb = Mathf.Min(toAbsorb, CurrentShieldHP);
|
||||
int passthrough = amount - toAbsorb;
|
||||
|
||||
CurrentShieldHP -= toAbsorb;
|
||||
OnShieldChanged?.Invoke(CurrentShieldHP, maxHP);
|
||||
|
||||
if (CurrentShieldHP <= 0)
|
||||
{
|
||||
CurrentShieldHP = 0;
|
||||
_brokenPenaltyTimer = BrokenPenaltyDur;
|
||||
OnShieldBroken?.Invoke();
|
||||
_onShieldBrokenChannel?.Raise(); // VFX 钩子:播放护盾破碎特效
|
||||
}
|
||||
|
||||
return passthrough;
|
||||
}
|
||||
|
||||
/// <summary>存档点 / 复活时调用:完全恢复护盾并清除惩罚状态。</summary>
|
||||
public void FullRecharge()
|
||||
{
|
||||
bool wasBroken = _brokenPenaltyTimer > 0f || CurrentShieldHP <= 0;
|
||||
_brokenPenaltyTimer = 0f;
|
||||
_regenDelayTimer = 0f;
|
||||
CurrentShieldHP = MaxShieldHP;
|
||||
OnShieldChanged?.Invoke(CurrentShieldHP, MaxShieldHP);
|
||||
if (wasBroken)
|
||||
_onShieldRestoredChannel?.Raise(); // VFX 钩子:护盾已满血恢复
|
||||
}
|
||||
|
||||
/// <summary>弹反成功时调用:按 ParryRestoreRatio 恢复护盾(会清除惩罚状态)。</summary>
|
||||
public void OnParrySuccess()
|
||||
{
|
||||
int maxHP = MaxShieldHP;
|
||||
if (maxHP <= 0) return;
|
||||
|
||||
_brokenPenaltyTimer = 0f;
|
||||
_regenDelayTimer = 0f;
|
||||
int restore = Mathf.CeilToInt(maxHP * ParryRestoreRatio);
|
||||
CurrentShieldHP = Mathf.Min(CurrentShieldHP + restore, maxHP);
|
||||
OnShieldChanged?.Invoke(CurrentShieldHP, maxHP);
|
||||
}
|
||||
|
||||
/// <summary>Inspector / 道具系统调用:设置最大护盾并重置当前值。</summary>
|
||||
public void SetMaxShieldHP(int max)
|
||||
{
|
||||
_maxShieldHP = Mathf.Max(0, max);
|
||||
_brokenPenaltyTimer = 0f;
|
||||
CurrentShieldHP = MaxShieldHP;
|
||||
OnShieldChanged?.Invoke(CurrentShieldHP, MaxShieldHP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user