摄像机区域的架构改动

This commit is contained in:
2026-05-15 14:47:24 +08:00
parent 1b37297585
commit f264329751
3591 changed files with 1687228 additions and 446503 deletions

View File

@@ -0,0 +1,129 @@
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; // 由 PlayerController.Awake() 注入
private IPoiseSource _poiseSource; // 由 EnemyBase.Awake() 注入
private IStatusEffectable _statusEffectable; // Awake 缓存,避免每次受击调用 GetComponent
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;
#if UNITY_EDITOR
// 付给编辑器的只读属性——避免反射并限制编辑器与运行时字段名耐合性。
public object EditorOwner => _owner;
public object EditorShieldable => _shieldable;
public object EditorParrySystem => _parrySystem;
public object EditorPoiseSource => _poiseSource;
public object EditorStatusEffectable => _statusEffectable;
#endif
private void Awake()
{
_owner = GetComponentInParent<IDamageable>();
_statusEffectable = GetComponentInParent<IStatusEffectable>();
if (_owner == null)
Debug.LogWarning($"[HurtBox] {name}: 父节点中未找到 IDamageable 实现。", this);
}
/// <summary>
/// 接受伤害(由 HitBox.OnTriggerEnter2D 直接调用)。
/// <param name="hitPoint">弹击点世界坐标;不传则默认使用 HurtBox 节点中心。</param>
/// ⚠️ 方法名必须为 ReceiveDamage。
/// </summary>
public void ReceiveDamage(DamageInfo info, Vector3? hitPoint = null)
{
Vector3 resolvedHitPoint = hitPoint ?? transform.position;
if (!_isActive || _owner == null) return;
// 1. 无敌帧检查
if ((_owner.IsInvincible || _isHurtBoxInvincible)
&& !info.Flags.HasFlag(DamageFlags.IgnoreIFrame)) return;
// 2. 弹反检查_parrySystem == null 时跳过)
// ParrySystem 只暴露窗口状态,伤害数据留在 Combat 层,无跨程序集数据依赖。
if (_parrySystem != null && info.Flags.HasFlag(DamageFlags.CanBeParried))
if (_parrySystem.ConsumeParry()) return;
// 3. 霸体检查_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 = resolvedHitPoint,
});
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 = resolvedHitPoint,
});
// 8. 状态效果触发DoT — Fire / Poison
// _statusEffectable 已在 Awake 中缓存,无需每次受击调用 GetComponent
_statusEffectable?.ApplyStatusEffect(info.Type);
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
var col = GetComponent<Collider2D>();
if (col == null) return;
// HurtBox正常激活 = 青色,无敌 = 黄色,非激活 = 极淡青
Gizmos.color = !_isActive
? new Color(0f, 0.85f, 1f, 0.15f)
: _isHurtBoxInvincible
? new Color(1f, 1f, 0f, 1f )
: new Color(0f, 0.85f, 1f, 1f );
HitBox.DrawCollider2DWire(col);
}
#endif
}
}