角色能力,存档

This commit is contained in:
2026-05-19 11:50:21 +08:00
parent d25f237e76
commit 2dcb7a961a
136 changed files with 36035 additions and 27551 deletions

View File

@@ -5,58 +5,82 @@ namespace BaseGames.Player
{
/// <summary>
/// 武器 HitBox 实例。
/// 由 WeaponManager 在切换武器时实例化到角色的 [WeaponSocket] 子节点下
/// 武器卸下(切换)时销毁。
/// 由 WeaponManager 在切换武器时实例化到角色的 [WeaponSocket] 子节点下
///
/// Prefab 内部层级示例:
/// [WPN_SkyBlade_HitBox]
/// ├── [HitBox_Ground] ← BoxCollider2D, Layer = PlayerHitBox
/// ├── [HitBox_Up]
/// ├── [HitBox_Down]
/// ── [HitBox_Air]
/// Prefab 层级示例(每段连击独立一个子节点,在 Prefab 内可视化编辑 Collider2D
/// [WPN_SkyBlade_HitBox] ← WeaponHitBoxInstance
/// ├── [HitBox_Ground] Id="" ← 方向默认ComboStepConfig.hitBoxId 为空时使用)
/// ├── [HitBox_Ground_1] Id="g1" ← 第 1 段专属判定
/// ├── [HitBox_Ground_2] Id="g2" ← 第 2 段专属判定
/// ── [HitBox_Up] Id="" ← 上劈默认
/// ├── [HitBox_Down] Id="" ← 下劈默认
/// └── [HitBox_Air] Id="" ← 空中默认
///
/// 命名规范Assets/Prefabs/Weapons/WPN_{weaponId}_HitBox.prefab
/// ComboStepConfig.hitBoxId 留空 → 用方向默认;填 Id → 精确激活对应子节点。
/// </summary>
public class WeaponHitBoxInstance : MonoBehaviour
{
[Header("方向默认 HitBoxhitBoxId 为空时使用)")]
[SerializeField] private HitBox _hitBoxGround;
[SerializeField] private HitBox _hitBoxUp;
[SerializeField] private HitBox _hitBoxDown;
[SerializeField] private HitBox _hitBoxAir;
/// <summary>下劈 HitBox 命中确认事件(供 PlayerCombat 转发给 DownAttackState pogo 逻辑)。</summary>
private HitBox[] _allHitBoxes;
private AttackDirection _activeDir;
/// <summary>下劈命中确认事件(供 DownAttackState Pogo 逻辑)。</summary>
public event System.Action<DamageInfo> OnDownHitConfirmed;
private void Awake()
{
if (_hitBoxDown != null)
_hitBoxDown.OnHitConfirmed += info => OnDownHitConfirmed?.Invoke(info);
_allHitBoxes = GetComponentsInChildren<HitBox>(true);
foreach (var hb in _allHitBoxes)
hb.OnHitConfirmed += OnAnyHitConfirmed;
}
private void OnAnyHitConfirmed(DamageInfo info)
{
if (_activeDir == AttackDirection.Down)
OnDownHitConfirmed?.Invoke(info);
}
// ── 公共 API ──────────────────────────────────────────────────────────
/// <summary>激活指定方向的 HitBox。</summary>
public void Activate(AttackDirection dir, DamageSourceSO source, Transform attacker)
=> GetHitBox(dir)?.Activate(source, attacker);
/// <summary>停用指定方向的 HitBox。</summary>
public void Deactivate(AttackDirection dir)
=> GetHitBox(dir)?.Deactivate();
/// <summary>停用所有方向的 HitBox。</summary>
public void DeactivateAll()
/// <summary>
/// 激活 HitBox。
/// hitBoxId 非空时按 Id 精确查找 Prefab 子节点;空 = 使用该方向的默认 HitBox。
/// </summary>
public void Activate(AttackDirection dir, DamageSourceSO source, Transform attacker,
string hitBoxId = "")
{
_hitBoxGround?.Deactivate();
_hitBoxUp?.Deactivate();
_hitBoxDown?.Deactivate();
_hitBoxAir?.Deactivate();
_activeDir = dir;
var hitBox = string.IsNullOrEmpty(hitBoxId)
? GetHitBox(dir)
: (GetHitBoxById(hitBoxId) ?? GetHitBox(dir));
hitBox?.Activate(source, attacker);
}
/// <summary>切换连击段伤害源(不改变激活状态,供 PlayerCombat.SetComboSegmentSource 调用)。</summary>
public void SetDamageSource(AttackDirection dir, DamageSourceSO source)
=> GetHitBox(dir)?.SetDamageSource(source);
/// <summary>停用指定方向的默认 HitBox。</summary>
public void Deactivate(AttackDirection dir) => GetHitBox(dir)?.Deactivate();
/// <summary>按方向查询对应 HitBox 组件。</summary>
/// <summary>停用 Prefab 中所有 HitBox。</summary>
public void DeactivateAll()
{
if (_allHitBoxes == null) return;
foreach (var hb in _allHitBoxes) hb.Deactivate();
}
/// <summary>按 HitBox.Id 查找子节点(未找到返回 null。</summary>
public HitBox GetHitBoxById(string id)
{
if (_allHitBoxes == null || string.IsNullOrEmpty(id)) return null;
foreach (var hb in _allHitBoxes)
if (hb.Id == id) return hb;
return null;
}
/// <summary>按攻击方向返回默认 HitBox。</summary>
public HitBox GetHitBox(AttackDirection dir) => dir switch
{
AttackDirection.Ground => _hitBoxGround,