Files
zeling_v2/Docs/Design/54_PoiseSystem.md
2026-05-08 11:04:00 +08:00

703 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 54 · 霸体系统Poise / Superarmor System
> **命名空间** `BaseGames.Combat`
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **依赖** `BaseGames.Combat`DamageInfo / HitBox / HurtBox· `BaseGames.Skills`FormSkillSO· `BaseGames.Enemies.Boss.Skills`BossSkillSO
---
## 目录
1. [系统总览](#1-系统总览)
2. [核心枚举定义](#2-核心枚举定义)
3. [霸体窗口配置PoiseWindowConfig](#3-霸体窗口配置poiseswindowconfig)
4. [IPoiseSource — 霸体来源接口](#4-ipoisesource--霸体来源接口)
5. [HurtBox 打断判定流水线](#5-hurtbox-打断判定流水线)
6. [DamageInfo / DamageSourceSO 扩展](#6-damageinfo--damagesourceso-扩展)
7. [玩家霸体配置](#7-玩家霸体配置)
- [7.1 攻击状态霸体](#71-攻击状态霸体)
- [7.2 技能施放霸体FormSkillSO](#72-技能施放霸体formskillso)
- [7.3 能力状态霸体](#73-能力状态霸体)
8. [敌人 / Boss 霸体配置BossSkillSO](#8-敌人--boss-霸体配置bossskillso)
9. [显式打断关系表PoiseOverrideTableSO](#9-显式打断关系表poiseoverridetableso)
10. [全动作霸体参考表](#10-全动作霸体参考表)
11. [平衡设计准则](#11-平衡设计准则)
12. [编辑器友好设计](#12-编辑器友好设计)
---
## 1. 系统总览
**霸体Poise** 是动作游戏中"受击时不被打断"的能力。本系统将霸体和打断能力拆解为两个对立等级,并通过 SO 数据驱动实现对**所有技能、攻击、能力**的精细配置。
### 核心概念
| 概念 | 说明 |
|------|------|
| **霸体等级PoiseLevel** | 当前动作抵抗被打断的强度。等级越高,越难被打断。 |
| **打断等级BreakLevel** | 攻击/技能的打断能力。等级越高,能打断越强的霸体。 |
| **霸体窗口Poise Window** | 某个动作在哪段时间内拥有霸体(可以是整个状态,也可以是特定动画帧区间)。 |
| **霸体 vs 无敌帧IFrame** | 无敌帧 = 不受任何伤害;霸体 = 受伤但不被打断,两者独立,可同时生效。 |
### 打断判定规则
```
受击时:
1. 检查无敌帧IFrame → 若活跃,直接跳过所有伤害处理
2. 检查打断逻辑:
a. 查询 PoiseOverrideTable 是否有该攻击 vs 该状态的显式规则
→ 若有 AlwaysInterrupt: 强制打断Unbreakable 除外)
→ 若有 NeverInterrupt: 绝不打断(保留伤害)
b. 默认规则:(int)incomingBreakLevel >= (int)currentPoiseLevel → 打断
3. 若打断:进入 HurtState / 施加击退 / 技能 / 动作被取消
若不打断:仅扣血 + 播放受击闪烁,不进入 HurtState
```
```
装备系统
职责图:
├─ PoiseLevel / BreakLevel → 两个对立枚举(等级比较核心)
├─ PoiseWindowConfig → 结构体(哪段时间有霸体,霸体等级)
├─ IPoiseSource → 接口(状态/技能/动作暴露当前霸体等级)
├─ DamageSourceSO → 增加 breakLevel 字段
├─ DamageInfo → 增加 BreakLevel 字段
├─ HurtBox → 打断判定逻辑
├─ FormSkillSO → 技能施放期间的霸体窗口
├─ BossSkillSO → Boss 技能执行期间的霸体配置
├─ PlayerStateBase → 玩家状态暴露 CurrentPoise
└─ PoiseOverrideTableSO → 显式打断关系配置(可选精细控制)
```
---
## 2. 核心枚举定义
```csharp
namespace BaseGames.Combat
{
/// <summary>
/// 霸体等级:当前动作抵抗被打断的强度。
/// Unbreakable = 100任何 BreakLevel 均无法打断BOSS 阶段转换技、玩家特定能力专用)。
/// </summary>
public enum PoiseLevel
{
None = 0, // 无霸体:任何攻击均可打断(普通状态、普通敌人站立)
Light = 1, // 轻霸体可被中级以上攻击打断普通攻击第3段可打断
Medium = 2, // 中霸体:只有重型攻击或技能可打断(精英怪冲刺、玩家技能施放)
Heavy = 3, // 重霸体只有破甲攻击可打断Boss 核心攻击前摇)
Unbreakable = 100, // 霸体完全不可打断Boss 阶段过渡、剧情硬直)
}
/// <summary>
/// 打断等级:攻击/技能打断对手霸体的能力。
/// 判定规则:(int)breakLevel >= (int)targetPoiseLevel 时发生打断Unbreakable 例外)。
/// </summary>
public enum BreakLevel
{
None = 0, // 无打断力(弱攻击,只能打断 PoiseLevel.None
Light = 1, // 轻打断(可打断 Light 及以下霸体)
Medium = 2, // 中打断(可打断 Medium 及以下霸体)
Heavy = 3, // 重打断(可打断 Heavy 及以下霸体)
Breaker = 4, // 破甲(可打断 Heavy 及以下,不能打断 Unbreakable
}
}
```
### 打断关系速查矩阵
| **BreakLevel →** | None(0) | Light(1) | Medium(2) | Heavy(3) | Breaker(4) |
|:---:|:---:|:---:|:---:|:---:|:---:|
| **PoiseLevel.None(0)** | ✅打断 | ✅打断 | ✅打断 | ✅打断 | ✅打断 |
| **PoiseLevel.Light(1)** | ❌ | ✅打断 | ✅打断 | ✅打断 | ✅打断 |
| **PoiseLevel.Medium(2)** | ❌ | ❌ | ✅打断 | ✅打断 | ✅打断 |
| **PoiseLevel.Heavy(3)** | ❌ | ❌ | ❌ | ✅打断 | ✅打断 |
| **PoiseLevel.Unbreakable** | ❌ | ❌ | ❌ | ❌ | ❌ |
> 所有 ❌ 情况:仍扣血,但**不进入 HurtState不施加击退**。
---
## 3. 霸体窗口配置PoiseWindowConfig
```csharp
/// <summary>
/// 霸体窗口配置。定义某动作在哪段时间内(以动画时间轴为基准)拥有霸体。
/// - 若 windowStart = windowEnd = 0则整个动作期间均拥有霸体。
/// - windowStart/End 使用归一化时间0.0 = 动画起始1.0 = 动画结束)。
/// </summary>
[Serializable]
public struct PoiseWindowConfig
{
[Tooltip("霸体等级None = 无霸体Unbreakable = 完全不可打断)")]
public PoiseLevel level;
[Tooltip("霸体生效起始时间归一化0 = 动画开始。0+0 = 全程霸体。")]
[Range(0f, 1f)]
public float windowStart;
[Tooltip("霸体生效结束时间归一化0 = 动画结束 = 1.0 等价。0+0 = 全程霸体。")]
[Range(0f, 1f)]
public float windowEnd;
/// <summary>是否在整个动作期间都有霸体windowStart = windowEnd = 0 时视为全程)</summary>
public bool IsFullDuration => windowStart == 0f && windowEnd == 0f;
/// <summary>检查指定归一化时间是否在霸体窗口内</summary>
public bool IsActiveAt(float normalizedTime)
{
if (level == PoiseLevel.None) return false;
if (IsFullDuration) return true;
return normalizedTime >= windowStart && normalizedTime <= windowEnd;
}
/// <summary>预设:全程轻霸体</summary>
public static PoiseWindowConfig LightFull
=> new() { level = PoiseLevel.Light, windowStart = 0, windowEnd = 0 };
/// <summary>预设:全程中霸体</summary>
public static PoiseWindowConfig MediumFull
=> new() { level = PoiseLevel.Medium, windowStart = 0, windowEnd = 0 };
/// <summary>预设:全程重霸体</summary>
public static PoiseWindowConfig HeavyFull
=> new() { level = PoiseLevel.Heavy, windowStart = 0, windowEnd = 0 };
/// <summary>预设:无霸体</summary>
public static PoiseWindowConfig None
=> new() { level = PoiseLevel.None, windowStart = 0, windowEnd = 0 };
}
```
---
## 4. IPoiseSource — 霸体来源接口
所有可以提供霸体的对象玩家状态、技能执行器、Boss 技能执行器)实现此接口:
```csharp
/// <summary>
/// 霸体来源接口。HurtBox 在打断判定时调用此接口查询当前霸体等级。
/// </summary>
public interface IPoiseSource
{
/// <summary>当前霸体等级(实时,随动画帧变化)</summary>
PoiseLevel CurrentPoise { get; }
}
```
**玩家端实现**`PlayerController` 汇总多个 `IPoiseSource`(当前状态 + 技能执行器)并对外暴露最高霸体等级:
```csharp
public class PlayerController : MonoBehaviour, IPoiseSource
{
// 汇总当前所有霸体来源,取最高等级
public PoiseLevel CurrentPoise
{
get
{
PoiseLevel best = _currentState?.CurrentPoise ?? PoiseLevel.None;
PoiseLevel skill = _skillManager.CurrentPoise;
return (int)skill > (int)best ? skill : best;
}
}
}
```
---
## 5. HurtBox 打断判定流水线
`HurtBox.ReceiveDamage(DamageInfo)` 新增霸体检查步骤:
```csharp
public void ReceiveDamage(DamageInfo info)
{
// ── Step 1: 无敌帧检查 ──────────────────────────────────────────────────
if (_owner is IInvincible inv && inv.IsInvincible && !info.Flags.HasFlag(DamageFlags.IgnoreIFrame))
return;
// ── Step 2: 计算最终伤害 ─────────────────────────────────────────────────
int finalDamage = info.DamageType == DamageType.True
? info.RawDamage
: Mathf.Max(1, info.RawDamage - _defenseStat);
// ── Step 3: 霸体打断检查 ─────────────────────────────────────────────────
bool interrupted = ShouldInterrupt(info);
// ── Step 4: 应用伤害 ─────────────────────────────────────────────────────
_owner.TakeDamage(finalDamage);
OnHitConfirmedChannel.Raise(info);
OnHurt.Invoke(info);
// ── Step 5: 条件性打断 ────────────────────────────────────────────────────
if (interrupted)
{
_owner.ApplyKnockback(info);
_owner.ForceState(HurtState); // 取消当前动作,进入硬直
}
else
{
// 仅播放受击闪烁/震屏,不打断动作
_owner.PlayHitFlash();
}
}
/// <summary>综合三层规则判断是否发生打断</summary>
bool ShouldInterrupt(DamageInfo info)
{
// 获取当前霸体等级
PoiseLevel poise = (_owner as IPoiseSource)?.CurrentPoise ?? PoiseLevel.None;
// Unbreakable 不可打断(即使有 ForceBreak 标记)
if (poise == PoiseLevel.Unbreakable) return false;
// Layer 1: 显式 PoiseOverrideTable 查询
if (_overrideTable != null)
{
PoiseOverrideResult? ov = _overrideTable.Query(info.SourceId, _owner.StateId);
if (ov == PoiseOverrideResult.AlwaysInterrupt) return true;
if (ov == PoiseOverrideResult.NeverInterrupt) return false;
}
// Layer 2: DamageFlags.ForceBreak — 无视霸体等级Unbreakable 已在上面拦截)
if (info.Flags.HasFlag(DamageFlags.ForceBreak)) return true;
// Layer 3: 默认数值比较
return (int)info.BreakLevel >= (int)poise;
}
```
### 新增 DamageFlags
```csharp
public enum DamageFlags
{
// ... 原有 flags ...
CanBeParried = 1 << 0,
Unblockable = 1 << 1,
IgnoreIFrame = 1 << 2,
PerfectParryOnly = 1 << 3,
IsProjectile = 1 << 4,
CanClash = 1 << 5,
// 新增
ForceBreak = 1 << 6, // 强制打断目标当前动作忽略霸体等级Unbreakable 除外)
NoKnockback = 1 << 7, // 打断时不施加击退(仅进入 HurtState 硬直)
}
```
---
## 6. DamageInfo / DamageSourceSO 扩展
### DamageInfo 新增字段
```csharp
public struct DamageInfo
{
// ... 原有字段 ...
/// <summary>
/// 此次攻击的打断等级。由 DamageSourceSO.breakLevel 赋值,
/// 弹射物等特殊攻击由创建者手动指定。
/// </summary>
public BreakLevel BreakLevel;
/// <summary>
/// 攻击来源标识(用于 PoiseOverrideTable 查询)。
/// 格式DamageSourceSO.sourceId 或 SkillSO.skillId。
/// </summary>
public string SourceId;
}
```
### DamageSourceSO 新增字段
```csharp
public class DamageSourceSO : ScriptableObject
{
// ... 原有字段 ...
[Header("霸体系统")]
[Tooltip("此攻击的打断等级(决定能打断多高的霸体)")]
public BreakLevel breakLevel = BreakLevel.None;
[Tooltip("是否强制打断ForceBreak—— 无视目标霸体等级Unbreakable 除外")]
public bool forceBreak = false;
}
```
`HitBox` 构建 `DamageInfo` 时:
```csharp
var info = new DamageInfo
{
// ... 原有赋值 ...
BreakLevel = _damageSource.breakLevel,
SourceId = _damageSource.sourceId,
// ForceBreak 标记
DamageFlags = _damageSource.forceBreak
? _damageSource.DamageFlags | DamageFlags.ForceBreak
: _damageSource.DamageFlags,
};
```
---
## 7. 玩家霸体配置
### 7.1 攻击状态霸体
`PlayerStateBase` 提供默认实现;`AttackState` 根据当前武器动画帧动态更新霸体等级:
```csharp
public abstract class PlayerStateBase : StateObject, IPoiseSource
{
/// <summary>此状态的默认霸体等级(子类可覆盖)</summary>
public virtual PoiseLevel CurrentPoise => PoiseLevel.None;
/// <summary>外部查询时使用的状态 ID用于 PoiseOverrideTable</summary>
public virtual string StateId => GetType().Name;
}
public class AttackState : PlayerStateBase
{
// 从当前武器 SO 读取当前段的霸体配置
public override PoiseLevel CurrentPoise
{
get
{
WeaponSO w = _weaponManager.ActiveWeapon;
PoiseWindowConfig cfg = _comboState switch
{
ComboState.Attack1 => w.attack1PoiseWindow,
ComboState.Attack2 => w.attack2PoiseWindow,
ComboState.Attack3 => w.attack3PoiseWindow,
ComboState.AirAttack => w.airAttackPoiseWindow,
ComboState.UpAttack => w.upAttackPoiseWindow,
ComboState.DownAttack => w.downAttackPoiseWindow,
_ => PoiseWindowConfig.None,
};
float t = _animancer.Layers[0].CurrentState?.NormalizedTime ?? 0f;
return cfg.IsActiveAt(t) ? cfg.level : PoiseLevel.None;
}
}
}
```
`WeaponSO` 新增攻击霸体窗口字段(见 [53_WeaponSystem §2](./53_WeaponSystem.md)
```csharp
[Header("霸体配置(每段攻击)")]
public PoiseWindowConfig attack1PoiseWindow; // 默认 None普通轻击无霸体
public PoiseWindowConfig attack2PoiseWindow;
public PoiseWindowConfig attack3PoiseWindow; // 通常配置 Light 霸体(重击前摇)
public PoiseWindowConfig airAttackPoiseWindow;
public PoiseWindowConfig upAttackPoiseWindow;
public PoiseWindowConfig downAttackPoiseWindow;
```
### 三形态武器攻击霸体预设
| 动作 | 天魂SkyBlade| 地魂EarthHammer| 命魂LifeScythe|
|------|:-----------:|:-----------:|:-----------:|
| Attack1 | None | None | None |
| Attack2 | None | None | None |
| Attack3 | Light0.0-0.5 前摇)| Medium全程| Light全程|
| AirAttack | None | None | None |
| UpAttack | None | None | None |
| DownAttack | None | None | None |
### 7.2 技能施放霸体FormSkillSO
`FormSkillSO` 新增 `poiseWindow` 字段:
```csharp
[Header("霸体配置")]
[Tooltip("技能施放期间的霸体窗口。None = 可被任何攻击打断。")]
public PoiseWindowConfig poiseWindow;
```
`SkillManager` 在技能施放期间作为 `IPoiseSource`
```csharp
public class SkillManager : MonoBehaviour, IPoiseSource
{
FormSkillSO _activeCastingSkill;
float _castStartTime;
public PoiseLevel CurrentPoise
{
get
{
if (_activeCastingSkill == null) return PoiseLevel.None;
float elapsed = Time.time - _castStartTime;
float duration = _activeCastingSkill.castLockDuration;
float normalized = Mathf.Clamp01(duration > 0 ? elapsed / duration : 1f);
return _activeCastingSkill.poiseWindow.IsActiveAt(normalized)
? _activeCastingSkill.poiseWindow.level
: PoiseLevel.None;
}
}
}
```
**九种技能施放霸体预设**
| 技能 | 形态 | 效果类型 | poiseWindow |
|------|------|---------|------------|
| 裂空掌 | 天魂 | MeleeAoE | `Light(0.0-0.6)` — 出手前摇有轻霸体 |
| 漩灵击 | 天魂 | BarrierAura | `Medium(全程)` — 护盾持续期间中霸体 |
| 灵踪弹 | 天魂 | Projectile | `None` — 远程技能无前摇霸体 |
| 地行术 | 地魂 | GroundDive | `Unbreakable(全程)` — 入地期间完全无敌 |
| 霸山拳 | 地魂 | MeleeAoE | `Heavy(0.0-0.4)` — 蓄力起手重霸体 |
| 魂元爆 | 地魂 | DelayedExplosion | `Light(0.0-0.3)` — 放置前摇轻霸体 |
| 登龙蹴 | 命魂 | DragonKick | `Heavy(全程)` — 升龙整段重霸体 |
| 太虚斩 | 命魂 | WraithDash | `Medium(全程)` — 冲刺中霸体 |
| 残阴术 | 命魂 | ShadowDecoy | `None` — 残影技能无霸体 |
### 7.3 能力状态霸体
| 状态类 | `CurrentPoise` 返回值 | 说明 |
|--------|---------------------|------|
| `IdleState` | `None` | 站立无霸体 |
| `RunState` | `None` | 跑动无霸体 |
| `AttackState` | 见 §7.1(动态) | 武器 SO 配置 |
| `DashState` | `None`(使用 IFrame 代替)| 冲刺靠无敌帧保护 |
| `AirState` | `None` | 空中无霸体 |
| `SpringState` | `Heavy` | 灵泉治疗全程重霸体(不可轻易打断)|
| `WallGrabState` | `Light` | 墙壁悬挂轻霸体(强击可推下)|
| `ParryState` | `Medium` | 弹反动作中霸体(弹反窗口内)|
| `HurtState` | `None` | 受击硬直无霸体 |
| `DeathState` | `Unbreakable` | 死亡动画完整播放 |
---
## 8. 敌人 / Boss 霸体配置BossSkillSO
`BossSkillSO` 新增霸体配置:
```csharp
// ─────────────────────────────
// 8. 霸体配置(新增)
// ─────────────────────────────
[Header("霸体配置")]
[Tooltip("此技能执行期间的霸体窗口None = 可被玩家攻击打断)")]
public PoiseWindowConfig poiseWindow;
```
`AttackPatternSO``19_BossPatternLibrary`)也添加打断等级,以描述**单次动作模式**的打断能力:
```csharp
[Header("打断能力")]
[Tooltip("此攻击动作对玩家霸体的打断等级")]
public BreakLevel breakLevel = BreakLevel.Light;
```
### Boss 技能霸体分类建议
| Boss 技能类型 | 推荐 poiseWindow |
|-------------|----------------|
| `Melee` 近战普通攻击 | `Light(全程)` |
| `Charge` 冲刺突进 | `Medium(全程)` |
| `AoE` 大范围爆炸 | `Heavy(0.0-0.5 蓄力段)` |
| `Phase` 阶段转换 | `Unbreakable(全程)` |
| `Reactive` 反制技 | `Medium(全程)` |
| `Buff` 自身增益 | `Heavy(全程)` |
| `Summon` 召唤技 | `Light(全程)` |
### 普通敌人霸体EnemyBase 扩展)
普通敌人通过 `EnemyConfigSO` 配置站立/攻击状态的霸体等级:
```csharp
[Header("霸体配置")]
public PoiseLevel idlePoise = PoiseLevel.None; // 站立/游荡时
public PoiseLevel attackPoise = PoiseLevel.Light; // 攻击动作时
public PoiseLevel staggerThreshold = PoiseLevel.None; // 受到同级霸体时触发僵直动画
```
---
## 9. 显式打断关系表PoiseOverrideTableSO
当默认数值规则不满足精细设计需求时,`PoiseOverrideTableSO` 允许指定**特定攻击 vs 特定状态**的强制规则:
```csharp
namespace BaseGames.Combat
{
/// <summary>
/// 显式打断关系配置表。HurtBox 在数值比较前优先查询此表。
/// 用于设计"某 Boss 技能无论玩家霸体多高都必须打断"等特殊场合。
/// </summary>
[CreateAssetMenu(menuName = "Combat/PoiseOverrideTable")]
public class PoiseOverrideTableSO : ScriptableObject
{
public List<PoiseOverrideEntry> entries;
public PoiseOverrideResult? Query(string attackSourceId, string targetStateId)
{
foreach (var e in entries)
{
bool matchAtk = string.IsNullOrEmpty(e.attackSourceId)
|| e.attackSourceId == attackSourceId;
bool matchTarget = string.IsNullOrEmpty(e.targetStateId)
|| e.targetStateId == targetStateId;
if (matchAtk && matchTarget)
return e.alwaysInterrupt
? PoiseOverrideResult.AlwaysInterrupt
: PoiseOverrideResult.NeverInterrupt;
}
return null; // 无显式规则,走默认数值逻辑
}
}
[Serializable]
public class PoiseOverrideEntry
{
[Tooltip("攻击来源 IDDamageSourceSO.sourceId 或 skillId。留空 = 匹配所有攻击来源。")]
public string attackSourceId;
[Tooltip("被打断状态 IDPlayerStateBase.StateId 或 BossSkillSO.skillId。留空 = 匹配所有状态。")]
public string targetStateId;
[Tooltip("true = 强制打断无视目标霸体等级Unbreakable 除外)")]
public bool alwaysInterrupt;
[Tooltip("true = 永不打断(无视打断等级,受击仅扣血)")]
public bool neverInterrupt;
[TextArea(1, 2)]
[Tooltip("记录此规则的设计原因")]
public string designNote;
}
public enum PoiseOverrideResult { AlwaysInterrupt, NeverInterrupt }
}
```
**资产存放**`Assets/ScriptableObjects/Combat/PoiseOverrideTable.asset`
**配置示例**
```
// 规则 1: Boss"虚空起源"的阶段2核心技能"星陨重压"强制打断玩家地行术(即使地行术是 Unbreakable
attackSourceId = "VoidOrigin_StarCrash"
targetStateId = "GroundDiveState"
alwaysInterrupt = true ← 注意:此处会覆盖 Unbreakable慎用
designNote = "设计意图:玩家不能通过地行术无伤躲过阶段技"
// 规则 2: 玩家弹反成功后的反击ParryCounter永不被任何敌人打断
attackSourceId = "" // 空 = 所有攻击来源
targetStateId = "ParryCounterState"
neverInterrupt = true
designNote = "弹反反击动作不应被打断,维护弹反奖励感"
// 规则 3: 精英敌人"石甲虫"的普通攻击对玩家施放天魂所有技能均无法打断
attackSourceId = "StoneArmadillo_Attack"
targetStateId = "" // 空 = 所有玩家状态
neverInterrupt = true
designNote = "石甲虫攻击较弱,不应打断任何玩家行动"
```
---
## 10. 全动作霸体参考表
### 玩家攻击打断等级
| 动作 | 天魂 BreakLevel | 地魂 BreakLevel | 命魂 BreakLevel |
|------|:-----------:|:-----------:|:-----------:|
| Attack1 | Light | Medium | Light |
| Attack2 | Light | Medium | Light |
| Attack3 | Medium | Heavy | Medium |
| AirAttack | Light | Medium | Light |
| UpAttack | Light | Medium | Light |
| DownAttackPogo| Light | Medium | Light |
| ParryCounter | Heavy | Heavy | Heavy |
> 地魂武器整体打断等级高一级,体现"重击"特性。
### 玩家技能打断等级
| 技能 | BreakLevel | 说明 |
|------|:----------:|------|
| 裂空掌 | Heavy | 近战 AoE高打断 |
| 漩灵击 | Medium | 护体,打断中等 |
| 灵踪弹 | Light | 弹射物,轻打断 |
| 地行术 | None | 入地,无接触打断 |
| 霸山拳 | Breaker | 破甲重拳 |
| 魂元爆 | Medium | 爆炸,中等打断 |
| 登龙蹴 | Heavy | 升龙,高打断 |
| 太虚斩 | Medium | 冲刺斩,中打断 |
| 残阴术(残影攻击)| Light | 残影,轻打断 |
### 能力状态打断等级(玩家被击时视角)
(参见 §7.3 能力状态霸体表)
---
## 11. 平衡设计准则
### 玩家侧
1. **普通连击段Attack1/2** 一般不给霸体,保持高风险高收益的近身博弈感
2. **第三段Attack3**`Light``Medium` 霸体,奖励打完完整连击的玩家
3. **重要技能施放**(霸山拳、登龙蹴)给 `Medium``Heavy` 霸体,让技能"值得放"
4. **灵泉治疗**`Heavy` 霸体,保证玩家有机会用完一个治疗不被打断
5. **冲刺** 使用 IFrame 而非霸体(短距离无敌,不受霸体系统管辖)
### 敌人侧
1. **普通敌人攻击** BreakLevel 统一为 `Light`(只能打断无霸体动作)
2. **精英怪攻击** BreakLevel 可到 `Medium`(能打断玩家轻霸体)
3. **Boss 核心技能** BreakLevel 可到 `Heavy``Breaker`(压制玩家大部分动作)
4. **Boss 蓄力/前摇** poiseWindow 给 `Heavy`,让玩家意识到"这招不能被随意取消"
### 禁止事项
| 禁止 | 原因 |
|------|------|
| 给 `Unbreakable` 的攻击设置 `PoiseOverrideEntry.alwaysInterrupt` | 会破坏设计安全感,须经负责人审核 |
| 玩家普通攻击 BreakLevel ≥ Heavy | 普通攻击打断 Boss 重霸体会让 Boss 失去压迫感 |
| BreakLevel = Breaker 的弹射物 | 远程破甲会使近战霸体设计失去意义 |
---
## 12. 编辑器友好设计
### HurtBox Gizmo 可视化
运行时暂停时HurtBox 的 Gizmo 显示:
```
受击对象: Player
当前状态: AttackState (Attack3)
当前霸体: Medium [窗口 0.0 ~ 1.0 全程]
最近受击: DS_Boss_Charge (BreakLevel: Heavy)
打断结果: ✅ Interrupted (Heavy >= Medium)
```
### PoiseOverrideTable 编辑器窗口
`Tools → Zeling → Poise Override Table`
```
┌─ Poise Override Table ─────────────────────────────────────┐
│ [自动验证:检查 attackSourceId / targetStateId 是否存在] │
│ │
│ # | 攻击来源 | 目标状态 | 类型 │
│ 1 | VoidOrigin_Star | GroundDiveState | AlwaysBreak │
│ 2 | (全部) | ParryCounterState | NeverBreak │
│ ... │
│ [+ 添加规则] [导出 CSV] [验证全部] │
└────────────────────────────────────────────────────────────┘
```
自动验证会检查:
- `attackSourceId` 对应的 `DamageSourceSO` / `FormSkillSO` / `BossSkillSO` 是否存在
- `targetStateId` 对应的 `PlayerStateBase` 子类或 `BossSkillSO.skillId` 是否存在
- 是否同时勾选 `alwaysInterrupt``neverInterrupt`(互斥,报错)