703 lines
26 KiB
Markdown
703 lines
26 KiB
Markdown
# 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 | Light(0.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("攻击来源 ID(DamageSourceSO.sourceId 或 skillId)。留空 = 匹配所有攻击来源。")]
|
||
public string attackSourceId;
|
||
|
||
[Tooltip("被打断状态 ID(PlayerStateBase.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 |
|
||
| DownAttack(Pogo)| 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`(互斥,报错)
|