Files
AIC-Project/Doc/minigame/横版3D格斗小游戏_开发设计文档.md
T

1277 lines
70 KiB
Markdown
Raw 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.
# 横版 3D 格斗小游戏开发设计文档
**2.5D · 1v1 · 帧数据驱动 · 单机原型基线**
| **版本** | v1.0 |
|--------------|------------------------------------|
| **日期** | 2026-08-10 |
| **技术基线** | 引擎无关;示例采用 Unity / C# 命名 |
> 目标:用最小但正确的战斗架构,实现行走、跳跃、格挡、拳脚、必杀技、超必杀技、命中反馈与完整回合流程;同时为后续角色扩展、训练模式和回滚联机保留清晰边界。
| **核心战斗** | **数据驱动** | **可验证** |
| --- | --- | --- |
| 输入缓冲 · 状态机 · 命中结算 | 招式帧表 · 判定轨迹 · 资源规则 | 帧步进 · Hitbox 调试 · 验收用例 |
**DOCUMENT CONTROL**
# 文档控制与阅读说明
本文档是面向小型团队或个人开发者的可执行设计基线。它同时覆盖玩法规则、核心战斗技术方案、数据结构、调试工具、开发计划与验收标准。所有数值均为首轮灰盒原型建议值,应通过手感测试迭代。
| **字段** | **内容** |
|------------------|----------------------------------------------------|
| **项目类型** | 横版 3D(2.5D)1v1 对战格斗小游戏 |
| **首发平台** | PC;键盘与手柄;本地双人或玩家对 AI |
| **画面实现** | 3D 角色与场景,战斗逻辑约束在水平轴与垂直轴 |
| **战斗基线** | 固定 60 Tick;帧数据驱动;运动学角色控制器 |
| **参考代码风格** | Unity / C# 命名;可映射至 Unreal、Godot 或自研引擎 |
| **目标读者** | 程序、策划、动画、特效、测试与制作人 |
> **关键边界**
>
> MVP 不做联网、投技、复杂防御资源、角色养成与剧情。先确保“输入可靠、状态可控、命中可解释、帧数据可调”,再增加内容。
## 术语约定
| **术语** | **定义** |
|--------------------------------|-------------------------------------------------------------------------------|
| **战斗 Tick** | 战斗逻辑更新单位;固定为每秒 60 次,与渲染帧率解耦。 |
| **起手 / 持续 / 收招** | Startup / Active / Recovery;攻击从输入到判定生效,再到恢复可行动的三个阶段。 |
| **HitStop** | 命中瞬间双方短暂停顿,用于强化重量感;不等同于受击硬直。 |
| **HitStun / BlockStun** | 命中硬直 / 格挡硬直;期间角色不能自由行动,但可受特定规则影响。 |
| **HitBox / HurtBox / PushBox** | 攻击判定 / 可受击判定 / 角色实体推挤判定。 |
| **取消窗口** | 允许当前动作提前转入指定动作的帧区间。 |
| **指令宽容** | 方向输入允许的总时间、相邻输入最大间隔、斜方向替代等容错规则。 |
## 目录
| **01 项目定位与设计目标** | **11 动画、特效、音效与镜头** |
|-----------------------------|-------------------------------|
| 02 MVP 范围与内容规格 | 12 技术架构与更新顺序 |
| 03 比赛规则与战斗空间 | 13 数据配置与资源规范 |
| 04 输入、缓冲与指令识别 | 14 UI、回合流程与设置 |
| 05 角色状态机与转移优先级 | 15 AI 与训练木桩 |
| **06 行走、跳跃与角色运动** | **16 性能、回放与联机预留** |
| 07 拳脚攻击与招式时间轴 | 17 调试工具与可观测性 |
| 08 格挡、防御与受击规则 | 18 开发里程碑与任务拆分 |
| 09 HitBox 与命中结算管线 | 19 测试方案与验收标准 |
| 10 必杀技、超必杀技与能量 | 20 风险、原创边界与附录 |
**PRODUCT VISION**
# 01 项目定位与设计目标
本项目是一款使用 3D 角色和场景、但将对战规则限制在二维战斗平面的 1v1 格斗小游戏。玩家通过走位、跳跃、格挡、拳脚、必杀技与超必杀技争夺回合胜利。重点不是堆叠招式数量,而是建立清晰、稳定、可调试的战斗内核。
## 1.1 玩家体验目标
- 输入响应明确:按键、方向与指令不会因为渲染帧率或动画事件而随机失效。
- 攻防结果可理解:为什么命中、为什么被格挡、为什么发生交易命中,都能通过调试数据解释。
- 打击有重量:命中停顿、受击动作、音效、火花、震屏与击退在同一事件上同步。
- 学习成本可控:MVP 只提供少量高辨识度招式,先形成“近身、对空、飞行道具、爆发技”的完整循环。
- 内容可扩展:新增角色主要通过配置数据、动画和判定轨迹完成,避免复制并修改大量角色逻辑。
## 1.2 核心循环
| **阶段** | **玩家行为** | **系统反馈** |
|-----------------|------------------------------|--------------------------------|
| **中立博弈** | 前后移动、试探、跳跃、预判 | 距离、站位、能量与时间形成压力 |
| **进攻确认** | 拳脚命中或迫使对手格挡 | HitStop、硬直、推远、命中特效 |
| **连段 / 取消** | 用轻攻击确认,再取消到必杀技 | 连击数、伤害缩放、资源增长 |
| **防守反击** | 格挡、后退、等待收招空隙 | 格挡硬直、削血、反击提示 |
| **资源爆发** | 积满能量后使用超必杀技 | 屏幕冻结、镜头强化、多段命中 |
| **回合结算** | KO 或时间结束 | 慢镜、胜负 UI、重开或下一回合 |
## 1.3 设计原则
> **1.** 战斗逻辑先于表现:战斗结果由数据与状态决定,动画、特效和镜头只消费结果。
>
> **2.** 整数帧优先:所有招式时序、无敌、取消与硬直均用战斗 Tick 表达。
>
> **3.** 单一结算入口:所有近战、飞行道具和超必杀命中都进入同一 HitResolver。
>
> **4.** 配置优先于分支:角色差异放入 CharacterData、MoveData 与 HitboxTrack,而不是散落在代码中的 if/else。
>
> **5.** 调试能力属于产品功能:从第一周就提供帧步进、输入历史和判定框显示。
> **成功标准**
>
> 两个相同灰盒角色也能玩出完整回合:走位可控、跳跃轨迹稳定、拳脚可命中/格挡、必杀与超杀可识别、KO 能结算;全流程无随机漏判和状态卡死。
**SCOPE**
# 02 MVP 范围与内容规格
## 2.1 首个可玩版本
| **优先级** | **功能** | **MVP 规格** |
|--------------|----------|----------------------------------------------------------|
| **P0 必须** | 角色移动 | 前走、后走、转身、蹲下、前跳、后跳、垂直跳、落地硬直 |
| **P0 必须** | 基础攻击 | 站立轻拳/重拳/轻脚/重脚,蹲轻脚,跳攻击;至少 6 个普通技 |
| **P0 必须** | 防御 | 按住背向方向格挡;站防、蹲防;格挡硬直、推远与削血规则 |
| **P0 必须** | 命中 | HitBox/HurtBox、HitStop、HitStun、击退、浮空、击倒、KO |
| **P0 必须** | 特殊招式 | 每角色 3 个必杀技:飞行道具、对空技、突进技 |
| **P0 必须** | 爆发资源 | 0–100 超必杀能量;每角色 1 个超必杀技 |
| **P0 必须** | 比赛流程 | 倒计时、生命、能量、局数、KO、时间结束、重开 |
| **P1 建议** | 对战对象 | 本地双人 + 简单 AI;训练木桩 |
| **P1 建议** | 调试 | 输入历史、帧计数、判定框、命中日志、帧步进 |
| **暂不实现** | 复杂系统 | 投技、拆投、空防、弹反、防御槽、角色养成、联网匹配 |
## 2.2 内容量建议
| **内容项** | **原型下限** | **首个完整 Demo** |
|--------------|------------------|---------------------------|
| **角色** | 1 个角色镜像对战 | 2 个原创角色 |
| **场景** | 1 个灰盒场景 | 1 个完整场景 + 1 个训练场 |
| **普通技** | 每角色 6 个 | 每角色 10–12 个 |
| **必杀技** | 每角色 2 个 | 每角色 3 个 |
| **超必杀技** | 每角色 1 个 | 每角色 1 个 |
| **AI 难度** | 1 档 | 3 档 |
| **回合规则** | 一局定胜负 | 三局两胜、99 秒 |
> **范围控制建议**
>
> 先用胶囊体、基础动作和纯色特效完成“第一可玩”;在手感通过前,不投入角色建模、复杂镜头和大量动作。任何新增功能都必须说明它改善了哪一种攻防决策。
## 2.3 非功能目标
- 标准 PC 在 1080p 下稳定 60 FPS;战斗 Tick 永远保持 60 Hz。
- 单次对战可从输入流重放,重放结果在同版本、同平台上保持一致。
- 角色招式数据修改后无需改核心代码即可生效。
- 战斗关键路径不产生持续 GC;飞行道具、命中特效和飘字使用对象池。
- 控制支持手柄与键盘重绑定,并提供震屏、闪光强度与输入显示开关。
**RULES & SPACE**
# 03 比赛规则与战斗空间
## 3.1 默认比赛规则
| **参数** | **默认值** | **说明** |
|----------------|------------------|------------------------------------|
| **局制** | 三局两胜 | 原型阶段可切换为一局定胜负 |
| **回合时间** | 99 秒 | 使用战斗时间;暂停与回合演出不计时 |
| **最大生命** | 1000 | 便于用整数表达伤害与缩放 |
| **超必杀能量** | 0100 | 命中、格挡与受击均可按招式配置增长 |
| **时间结束** | 生命百分比高者胜 | 相同则判平局并重开该回合 |
| **KO 判定** | 生命值 ≤ 0 | 本 Tick 结算完成后进入 KO 状态 |
## 3.2 坐标系与战斗平面
建议将 X 轴定义为左右移动,Y 轴定义为高度,Z 轴为场景深度。角色逻辑位置始终投影到固定的战斗平面 Z = 0;3D 模型可在表现层有轻微深度偏移,但 PushBox、HurtBox 与 HitBox 均在同一逻辑平面计算。
- 舞台边界:X ∈ \[StageHalfWidth, +StageHalfWidth\],角色中心不可越界。
- PushBox:两个角色不可穿透;先求期望位移,再按质量和边界分摊重叠量。
- 面对方向:每个 Tick 末根据双方 X 位置决定;攻击不可转身的帧区间保持原朝向。
- 交叉攻击:双方交换位置后,下一 Tick 更新面对方向;当前 Tick 的方向输入按 Tick 开始时朝向解释。
- 镜头:始终看向两人中点,并用距离和舞台边界控制缩放与平移。
## 3.3 战斗时间模型
> **固定战斗 Tick**
>
> 渲染可以是 60、120 或更高 FPS,但输入采样、状态推进、移动、碰撞与命中结算都以固定 1/60 秒为单位。动画播放速度由当前招式帧映射,不反过来驱动战斗结果。
| **时间域** | **是否受 HitStop 影响** | **典型内容** |
|----------------------|-------------------------|---------------------------------------|
| **BattleTime** | 是 | 招式帧、移动、飞行道具、受击/格挡硬直 |
| **PresentationTime** | 可选 | 粒子、镜头震动、音效尾音、UI 动画 |
| **RealTime** | 否 | 暂停菜单、设备重连、加载与调试界面 |
**INPUT**
# 04 输入、缓冲与指令识别
## 4.1 默认操作映射
| **动作** | **键盘示例** | **手柄示例** | **规则** |
|-------------|---------------|-----------------|------------------------------------|
| **方向** | WASD / 方向键 | 十字键 / 左摇杆 | 8 方向归一化;按角色朝向转换为前后 |
| **轻拳 LP** | J | X / □ | 快速、短距离、低伤害 |
| **重拳 HP** | K | Y / △ | 较慢、高伤害、可对空 |
| **轻脚 LK** | U | A / × | 中短距离、可做低段 |
| **重脚 HK** | I | B / ○ | 长距离、较大收招 |
| **暂停** | Esc | Menu / Options | 仅比赛允许时打开 |
*格挡默认不占独立按键:按住“远离对手”的方向进入格挡意图。可在辅助模式中增加 Guard 键。*
## 4.2 输入帧结构
每个渲染帧读取设备输入,将结果写入 InputBuffer;每个战斗 Tick 消费一个归一化输入快照。缓冲区建议保存最近 30–45 Tick,用于指令识别、输入显示、回放与问题复现。
| **字段** | **类型** | **用途** |
|--------------------|--------------|------------------------------------------|
| **Tick** | int | 输入发生的战斗 Tick |
| **Direction** | enum 1–9 | 数字小键盘方向;5 为中立 |
| **PressedMask** | bitmask | 本 Tick 新按下的攻击键 |
| **HeldMask** | bitmask | 本 Tick 持续按住的攻击键 |
| **ReleasedMask** | bitmask | 本 Tick 释放的攻击键;可用于负边输入扩展 |
| **FacingSnapshot** | Left / Right | 用于将世界方向转换为相对方向 |
| **ConsumedFlags** | bitmask | 避免同一次按键被多个动作重复消费 |
## 4.3 指令识别规则
- 方向按“相对朝向”解释:6 始终代表前,4 始终代表后。
- 从攻击键按下 Tick 向前回溯方向序列,而不是从最早输入向后搜索。
- 每条指令配置总窗口、相邻步骤最大间隔、是否允许斜方向替代、是否允许跳过中立。
- 同 Tick 多条指令成立时,按“超必杀 \> 必杀技 \> 特殊普通技 \> 普通技”排序。
- 动作进入后消费相关按键与方向片段,避免一个输入同时触发两个动作。
- 推荐首版宽容:必杀总窗口 12–16 Tick,超必杀 2024 Tick,按键缓冲 46 Tick。
| **招式类型** | **输入示例** | **匹配序列** | **宽容建议** |
|--------------|-----------------|--------------|-------------------------------------|
| **飞行道具** | ↓ ↘ → + P | 2, 3, 6 + P | 允许 2,6 或 2,3,6;总窗口 14 Tick |
| **对空技** | → ↓ ↘ + P | 6, 2, 3 + P | 允许首个 6 来自前走;总窗口 12 Tick |
| **突进技** | ↓ ↙ ← + K | 2, 1, 4 + K | 斜方向必须出现;总窗口 14 Tick |
| **超必杀** | ↓ ↘ → ↓ ↘ → + P | 236236 + P | 总窗口 24 Tick;能量必须为 100 |
**指令识别伪代码(方向相对角色朝向)**
```csharp
bool TryMatch(Command cmd, InputBuffer buffer, int nowTick, Facing facing) {
int cursor = nowTick;
for (int i = cmd.steps.Count - 1; i >= 0; --i) {
cursor = buffer.FindPreviousMatch(
cmd.steps[i], cursor, cmd.maxGapTicks, facing);
if (cursor < 0) return false;
}
return nowTick - cursor <= cmd.totalWindowTicks
&& buffer.HasButtonPress(cmd.buttonMask, nowTick, cmd.buttonBufferTicks);
}
```
> **输入可靠性验收**
>
> 在固定录制的 1000 组输入序列中,识别结果必须完全一致;切换渲染帧率、开启慢动作或发生 HitStop 时,不得改变指令成立结果。
**STATE MACHINE**
# 05 角色状态机与转移优先级
角色使用分层状态机:顶层区分 Ground、Air、Attack、Reaction、Down 与 KO,子状态负责行走、跳跃、攻击阶段和受击类型。状态机只处理“角色当前允许做什么”,招式帧表负责“某个动作在第几帧发生什么”。
```mermaid
flowchart LR
subgraph A["自然动作链"]
G["Ground<br/>Idle / Walk / Crouch / Turn"] -->|跳跃输入| JS["JumpStart"]
JS -->|起跳完成| AIR["Air<br/>Jump / Fall"]
AIR -->|接地| LAND["Landing"]
LAND -->|落地硬直结束| G
end
subgraph B["主动与防御分支"]
READY["Ground / Air<br/>当前可行动"] -->|攻击输入| ATK["Attack<br/>普通技 / 空中攻击"]
READY -->|指令成立| SP["Special / Super<br/>指令技 / 资源技"]
READY -->|有效格挡姿态| BLK["Block / BlockStun<br/>格挡意图 / 格挡硬直"]
ATK -->|动作结束| BACK["返回 Ground / Air"]
SP -->|动作结束| BACK
BLK -->|硬直结束| BACK
end
subgraph C["强制中断链(优先级高于普通输入)"]
NONKO["任意非 KO 状态"] -->|合法命中| HIT["HitStun / Launch<br/>站立受击 / 浮空"]
HIT -->|击倒| DOWN["Knockdown / Wakeup<br/>倒地 / 起身"]
DOWN -->|站立恢复或起身完成| GROUND["Ground"]
NONKO -->|生命归零| KO["KO / RoundEnd"]
HIT -->|受击阶段生命归零| KO
end
```
图 1 角色核心状态与主要转移
## 5.1 状态清单
| **状态组** | **子状态** | **关键职责** |
|--------------|-----------------------------------------------|----------------------------------------------------|
| **Ground** | Idle / Walk / Crouch / Turn | 读取移动与攻击输入;处理面对方向与地面摩擦 |
| **Air** | JumpStart / Jump / Fall / AirAttack / Landing | 处理起跳锁定、空中速度、接地与落地硬直 |
| **Attack** | Startup / Active / Recovery | 推进 MoveTimeline;开放 HitBox、取消窗口与位移曲线 |
| **Special** | Special / Super / Cinematic | 资源校验、无敌、飞行道具、屏幕冻结和多段命中 |
| **Defense** | Block / BlockStun | 格挡姿态、高低段校验、格挡硬直与推远 |
| **Reaction** | HitStun / Launch / WallBounce | 受击、浮空、击退、连段计数与恢复 |
| **Down** | Knockdown / Wakeup | 倒地时间、起身无敌与恢复站立 |
| **Terminal** | KO / RoundEnd | 禁用输入,播放结算动作与回合流程 |
## 5.2 转移优先级
同一 Tick 可能同时出现 KO、受击、落地、取消与新输入。为避免结果依赖代码调用顺序,所有转移先生成 TransitionRequest,再由统一优先级选择。建议顺序如下:
> **1.** KO / RoundEnd:生命归零或回合结束,覆盖所有普通转移。
>
> **2.** 强制受击:命中、击倒、浮空;无敌或装甲可在 HitResolver 阶段拦截。
>
> **3.** 脚本强制状态:超必杀演出、抓取演出(未来)、出生与回合开场。
>
> **4.** 取消转移:命中取消、格挡取消、特殊取消、超必杀取消。
>
> **5.** 接地 / 离地:落地、起跳帧结束、被击飞离地。
>
> **6.** 自然结束:收招、硬直、起身、转身结束。
>
> **7.** 玩家输入:走、蹲、跳、普通攻击、必杀技。
## 5.3 状态接口
**状态机接口建议**
```csharp
interface IFighterState {
void Enter(FighterContext ctx, StateEnterArgs args);
void PreTick(FighterContext ctx, in InputFrame input);
void Tick(FighterContext ctx); // 推进逻辑帧,不直接播放特效
void PostTick(FighterContext ctx); // 生成转移请求与表现事件
void Exit(FighterContext ctx);
}
struct TransitionRequest {
FighterStateId target;
int priority;
TransitionReason reason;
object payload;
}
```
> **避免的实现**
>
> 不要让 Animator StateMachineBehaviour 直接修改生命、开启判定或决定状态转移。动画事件可能因过渡、掉帧、速度变化或跳帧而漏发;它们最多用于非关键音效与装饰。
**MOVEMENT**
# 06 行走、跳跃与角色运动
## 6.1 运动学角色控制器
角色移动使用自定义 Kinematic FighterMotor,而不是依赖动态刚体。每个 Tick 计算期望速度与位移,执行舞台边界、地面检测和 PushBox 修正,再写回逻辑位置。这样能获得稳定、可重放且便于联网预留的结果。
| **参数** | **原型建议值** | **说明** |
|------------------|----------------|----------------------------------------|
| **前走速度** | 4.2 m/s | 接近对手时略快,鼓励主动走位 |
| **后走速度** | 3.4 m/s | 后退不应成为无成本脱离手段 |
| **蹲姿移动** | 0 m/s | MVP 中蹲下固定;后续可增加缓慢移动 |
| **跳跃初速度** | 8.5 m/s | 通过重力与初速度共同调整弧线 |
| **重力** | 28 m/s² | 建议自定义重力,不使用项目全局物理重力 |
| **空中水平速度** | 3.2 m/s | 起跳时锁定方向,允许少量空中修正可配置 |
| **落地硬直** | 4 Tick | 普通跳落地;空中攻击可配置更长硬直 |
| **PushBox 宽度** | 0.75 m | 站立基线;蹲姿可略小 |
*上述数值只用于灰盒验证;最终手感应以画面比例、角色身高和攻击距离统一调整。*
## 6.2 行走规则
- 方向输入为 6 时使用前走速度,4 时使用后走速度;“前/后”按角色面对方向解释。
- 攻击、格挡硬直、受击、倒地和大多数必杀技期间不读取普通行走输入。
- 进入 Turn 状态时可锁定 1–2 Tick,防止模型瞬间镜像造成脚步穿帮;逻辑朝向仍在规则允许时更新。
- 两个 PushBox 重叠时,先尝试各自退让一半;一方贴舞台边界时由另一方承担剩余位移。
- 不得用 CharacterController 的自动 StepOffset 造成 Z 轴或高度漂移;地面只允许设计好的坡度或平面。
## 6.3 跳跃规则
- 跳跃分为 JumpStart、Airborne、Landing。JumpStart 建议 34 Tick,期间可被命中。
- 起跳方向在 JumpStart 结束时锁定;垂直跳 X 速度为 0,前后跳使用各自速度。
- 空中不允许再次跳跃;是否允许空中格挡、空中必杀应由角色与招式数据显式配置。
- 接地判定使用脚底 Probe 与上一 Tick 高度,避免高速下落穿透地面。
- 被击飞时使用 ReactionVelocity,不复用普通跳跃状态,以便独立控制重力、弹地和受身。
**角色运动 Tick 伪代码**
```csharp
void SimulateMotor(Fighter f) {
Vec2 desired = f.State.BuildVelocity();
Vec2 delta = desired * BattleClock.FixedDelta;
delta = Stage.ClampToBounds(f.Position, delta, f.PushBox);
f.Position += delta;
PushSolver.ResolvePair(f, f.Opponent);
GroundProbe.ResolveLanding(f);
}
```
> **手感调试顺序**
>
> 先固定角色身高与舞台比例,再调走速和跳跃弧线;随后调攻击距离;最后才调镜头。镜头不能掩盖角色运动本身的问题。
**MOVE SYSTEM**
# 07 拳脚攻击与招式时间轴
## 7.1 普通攻击规格
每个普通技由 MoveData 描述,并由 MoveController 按 Tick 推进。MoveData 不仅记录起手/持续/收招,还包含位移、HitBox 轨迹、伤害、命中效果、取消窗口、资源变化和表现事件。
| **招式** | **定位** | **建议特征** |
|-----------------|---------------|--------------------------------------------------|
| **站轻拳 LP** | 近距离确认 | 4 Tick 起手;短收招;命中可连自身或取消必杀 |
| **站重拳 HP** | 高伤害 / 对空 | 810 Tick 起手;大 HitStop;可设置上半身对空判定 |
| **站轻脚 LK** | 中距离牵制 | 5 Tick 起手;较长脚部 HitBox;低伤害 |
| **站重脚 HK** | 远距离重击 | 10–12 Tick 起手;长收招;可造成击退或击倒 |
| **蹲轻脚 2LK** | 低段确认 | 低段;伤害低;命中后可接轻拳或必杀 |
| **跳重脚 j.HK** | 跳入攻击 | 空中可用;落地有硬直;根据落点决定正反向 |
## 7.2 招式阶段
| **阶段** | **逻辑** | **可发生事件** |
|--------------|--------------------------|------------------------------------------|
| **Startup** | 输入已接受,尚无攻击判定 | 前摇位移、无敌/装甲、取消来源检查 |
| **Active** | 一个或多个 HitBox 有效 | 命中、格挡、交易命中、多段间隔 |
| **Recovery** | HitBox 关闭,等待恢复 | 可被反击;部分招式开放命中取消 |
| **End** | 招式完成 | 返回 Idle / Air / Landing 或链入后续动作 |
## 7.3 取消规则
- Whiff Cancel:挥空时允许取消;MVP 默认关闭,避免无限安全试探。
- Hit Cancel:命中后允许普通技取消到指定必杀技。
- Block Cancel:被格挡时也可取消;通常比命中取消列表更严格。
- Chain Cancel:轻攻击可在命中后连到另一轻攻击或指定中攻击。
- Super Cancel:特定必杀技在命中/格挡时可取消为超必杀技。
- 取消只在 MoveData 的帧区间内有效,并且来源、目标、命中状态和资源条件全部满足。
## 7.4 连段与伤害缩放
| **规则** | **MVP 建议** |
|------------------|-----------------------------------------------------------|
| **连击成立** | 上一击造成的 HitStun 尚未结束,下一击在恢复前命中 |
| **伤害缩放** | 第 1 击 100%,第 2 击 90%,之后每击 10%,最低 50% |
| **最低伤害** | 超必杀最后一击可设 20% 最低保障,避免长连段完全失去终结感 |
| **HitStun 衰减** | 连击达到 5 段后每段额外减少 1 Tick,避免无限连 |
| **重复招式限制** | 同一浮空连段中关键弹墙/浮空属性只触发一次 |
| **连击重置** | 受击者回到可行动状态、倒地结束或回合结算时重置 |
> **帧优势的基本检查**
>
> 命中优势 ≈ HitStun − 攻击者剩余收招;格挡优势 ≈ BlockStun − 剩余收招。MVP 不要求复杂数值,但每个招式都应能从帧表推导“命中后谁先动、格挡后是否可反击”。
**DEFENSE**
# 08 格挡、防御与受击规则
## 8.1 格挡意图
格挡不是一个可以随时强制进入的普通动作,而是角色在可防御状态下、检测到“远离对手”的方向输入后产生的 GuardIntent。HitResolver 在命中 Tick 使用该意图、姿态和攻击段位决定是否格挡成功。
| **攻击段位** | **站立格挡** | **蹲下格挡** | **空中格挡** |
|------------------------|--------------|--------------|--------------|
| **High 高段** | 可 | 不可 | MVP 不支持 |
| **Mid 中段** | 可 | 可 | MVP 不支持 |
| **Low 低段** | 不可 | 可 | MVP 不支持 |
| **Unblockable 不可防** | 不可 | 不可 | 不可 |
## 8.2 格挡成立条件
- 受击者当前状态允许格挡:Idle、Walk、Crouch 或可取消到格挡的恢复状态。
- 在命中 Tick 开始时存在有效 GuardIntent;方向按该 Tick 的 FacingSnapshot 解释。
- 攻击段位与受击者姿态匹配;不可防或投技类攻击直接绕过。
- 受击者未处于 GuardBreak、KO、不可防演出或明确禁止格挡的动作中。
- 命中来自身后时,MVP 仍按双方逻辑朝向判定;下一 Tick 才更新转身,避免同 Tick 双重解释。
## 8.3 格挡结果
| **项目** | **建议规则** |
|--------------|---------------------------------------------------------------------|
| **格挡硬直** | 由攻击 MoveData 给出;轻攻击 69 Tick,重攻击 1218 Tick |
| **格挡推远** | 攻击者与防守者按比例分摊;角落时攻击者承担更多反作用位移 |
| **削血** | 普通技 0;必杀技 5%–15% 基础伤害;削血不能直接 KO(可配置) |
| **能量增长** | 攻击者命中格挡获得少量能量,防守者也获得更少能量 |
| **取消规则** | 攻击者可按 MoveData 在格挡后取消;防守者不可在 BlockStun 中普通行动 |
| **连续格挡** | BlockStun 期间若新攻击到达,重新计算段位并刷新硬直 |
## 8.4 受击类型
| **类型** | **用途** | **反应** |
|----------------|----------------------|----------------------------------|
| **LightHit** | 轻拳、轻脚 | 短 HitStop、轻微后仰、短硬直 |
| **HeavyHit** | 重拳、重脚、必杀 | 较长 HitStop、明显击退与受击动作 |
| **Launch** | 对空或浮空技 | 写入空中速度,进入 Launch 状态 |
| **Knockdown** | 扫腿、重击、超杀终结 | 落地后进入倒地与起身流程 |
| **Crumple** | 可选的重度受击 | 长站立硬直,可用于超杀前置 |
| **CounterHit** | 在对手攻击起手被命中 | 额外伤害或 HitStun,并显示提示 |
> **简化建议**
>
> MVP 先不做完美格挡、弹反、防御槽和受身。防御系统越复杂,越需要额外动画、UI、AI与平衡成本;先把高/中/低段与格挡硬直做正确。
**HIT DETECTION**
# 09 HitBox 与命中结算管线
## 9.1 判定体分类
| **判定体** | **归属** | **用途** | **实现建议** |
|------------------|----------------|--------------------------|--------------------------------------|
| **PushBox** | 角色 | 角色间实体推挤与角落挤压 | 固定矩形/胶囊;每 Tick 处理一次 |
| **HurtBox** | 角色骨骼或姿态 | 可被攻击命中的区域 | 头、躯干、腿等多个盒;随姿态轨迹变化 |
| **HitBox** | 招式或飞行道具 | 主动攻击判定 | 仅 Active 帧开启;携带 HitDefinition |
| **ProximityBox** | 可选 | 靠近时触发近身普通技 | 只用于选招,不直接造成命中 |
| **StageBox** | 场景 | 地面、边界与特殊区域 | 逻辑用简化体,视觉网格不参与战斗碰撞 |
## 9.2 判定轨迹
HitBox 与 HurtBox 不依赖运行时骨骼物理碰撞,而是由可编辑的 BoxTrack 描述。每个 Tick 根据招式帧或姿态帧读取局部位置、尺寸、旋转与标签,再转换到角色逻辑坐标。这样可以稳定调节判定,并在动画替换后保持规则可控。
- 优先使用矩形或胶囊;避免 MeshCollider 和复杂 Convex 碰撞。
- 每个 HitBox 携带 MoveInstanceId + HitGroupId,用于控制同一招式对同一目标的命中次数。
- 多段招式通过不同 HitGroup 或 RehitInterval 配置,不通过重复开关碰撞器猜测。
- 飞行道具使用独立 OwnerId、TeamId 与 ProjectileInstanceId,仍进入统一 HitResolver。
- 调试模式显示红色 HitBox、绿色 HurtBox、蓝色 PushBox,并标注 Tick 与招式 ID。
```mermaid
flowchart TD
S1["1. 收集同 Tick 的 HitBox × HurtBox 候选"] -->
S2["2. 过滤:阵营、自身、重复命中、无敌 / 装甲"] -->
S3["3. 判定格挡、高低段、交叉攻击与反击命中"] -->
S4["4. 处理同帧冲突:交易命中 / 显式优先级"] -->
S5["5. 计算伤害、连段缩放、削血与资源变化"] -->
S6["6. 写入 HitStop、HitStun / BlockStun、击退与浮空"] -->
S7["7. 派发视觉事件:特效、音效、震屏、慢镜头"] -->
S8["8. 记录 CombatLog 与回放输入,进入下一个 Tick"]
```
图 2 单个战斗 Tick 内的命中结算顺序
## 9.3 同帧冲突规则
| **场景** | **规则** |
|------------------------------|-----------------------------------------------------------------------|
| **双方普通攻击同 Tick 命中** | 默认交易命中:两边都应用结果;除非招式显式配置优先级或无敌 |
| **攻击命中飞行道具** | MVP 默认不相互抵消;后续可给飞行道具增加耐久与碰撞层 |
| **同一攻击命中多个 HurtBox** | 只生成一个 HitCandidate,使用命中点优先级最高的 HurtBox |
| **多段攻击同 Tick 重叠** | 按 HitGroupId 和 RehitInterval 去重;同目标每组最多结算一次 |
| **命中与 KO 同 Tick** | 先完成该 Tick 全部合法命中,再按结果进入 KO;表现上可选择超杀终结慢镜 |
| **格挡与被绕后同 Tick** | 按 Tick 开始时 FacingSnapshot 判断;下一 Tick 才转身 |
## 9.4 HitResult 数据
**统一命中结果对象**
```csharp
struct HitResult {
EntityId attacker;
EntityId defender;
MoveInstanceId moveInstance;
HitOutcome outcome; // Hit / Block / Armor / Invulnerable
int damage;
int chipDamage;
int hitStopAttacker;
int hitStopDefender;
int stunTicks;
Vec2 pushback;
Vec2 launchVelocity;
bool counterHit;
bool knockdown;
Vec2 contactPoint;
}
```
> **实现原则**
>
> 碰撞系统只回答“哪些判定体发生重叠”;HitResolver 才回答“这次重叠是否有效、是否格挡、造成多少伤害、进入什么状态”。不要把游戏规则写进 OnTriggerEnter。
**SPECIALS & SUPER**
# 10 必杀技、超必杀技与能量
## 10.1 必杀技组合建议
| **招式类型** | **战术作用** | **关键实现点** |
|--------------|----------------------------|---------------------------------------|
| **能量弹** | 远距离牵制、迫使跳跃或格挡 | 对象池、速度、寿命、命中组、场外回收 |
| **对空升击** | 惩罚跳跃、近身反击 | 起手无敌窗口、向上 HitBox、落地收招 |
| **突进踢** | 中距离接近、连段收尾 | 位移曲线、墙边推挤、命中/格挡不同收招 |
## 10.2 能量系统
| **事件** | **攻击者获得** | **防守者获得** |
|------------------|----------------|----------------|
| **普通技命中** | 25 | 13 |
| **普通技被格挡** | 13 | 12 |
| **必杀技命中** | 510 | 35 |
| **必杀技被格挡** | 36 | 24 |
| **受到重击** | — | 58 |
| **使用超必杀** | 消耗 100 | — |
*能量增长应全部来自 MoveData,不写死在攻击类型分支中。*
## 10.3 超必杀执行流程
> **1.** CommandRecognizer 检测到超必杀指令,并确认当前状态允许、能量为 100。
>
> **2.** 立即预占资源并创建 SuperMoveInstance,防止同 Tick 重复触发。
>
> **3.** 进入 815 Tick 的 SuperFreeze:对手、普通飞行道具与比赛计时暂停;施放者按配置推进或保持。
>
> **4.** 播放镜头拉近、角色闪光和蓄力音效;逻辑仍由 MoveTimeline 决定无敌与判定开启。
>
> **5.** 按多段 HitGroup 依次命中;每段有独立 HitStop、伤害与击退。
>
> **6.** 终结段应用 Knockdown 或特殊 KO 镜头;超杀结束后恢复正常镜头与 BattleTime。
| **规则项** | **建议** |
|--------------|-------------------------------------------------------|
| **超杀输入** | 236236 + 任意拳;总窗口 24 Tick,按键缓冲 5 Tick |
| **资源检查** | 必须在动作开始前满足;资源在 Enter 时扣除 |
| **起手无敌** | 示例 1–8 Tick;只作为招式数据,不由“超杀”类型自动赋予 |
| **画面冻结** | 逻辑冻结与表现冻结分离;UI、音效尾音可继续 |
| **连段缩放** | 遵循通用缩放,但终结段可有最低伤害保障 |
| **失败处理** | 资源不足时回退到普通拳;不可因指令部分匹配吞掉输入 |
> **原创性要求**
>
> 可以借鉴“飞行道具、对空、突进、超杀冻结”等类型设计,但角色造型、动作轮廓、招式名称、特效、音效、UI 与数值组合应原创,避免直接复刻现有作品。
**PRESENTATION**
# 11 动画、特效、音效与镜头
## 11.1 动画驱动策略
| **内容** | **权威来源** | **说明** |
|------------------|-----------------------------|--------------------------------|
| **当前动作与帧** | FighterState + MoveTimeline | 动画根据逻辑动作与 Tick 采样 |
| **HitBox 开关** | MoveData / HitboxTrack | 不依赖 Animation Event |
| **角色位移** | FighterMotor / MotionCurve | 普通战斗禁用自由 Root Motion |
| **受击与格挡** | HitResult | 结果确定后触发对应表现 |
| **音效与特效** | PresentationEvent | 允许丢帧补播,但不影响战斗结果 |
| **镜头** | CameraDirector | 消费角色位置与命中事件 |
## 11.2 动画状态建议
- 基础层:Idle、WalkF、WalkB、Crouch、Turn、JumpStart、JumpUp、Fall、Landing。
- 攻击层:每个普通技、必杀技与超必杀独立 Clip;按 MoveId 显式切换。
- 受击层:轻/重受击、上段/下段格挡、浮空、倒地、起身、KO。
- 面部或上半身叠加层仅用于非关键表现,不改变 HurtBox 和战斗姿态。
- 动画过渡时间应很短且可预测;攻击动作通常使用 0 或 1 Tick 的逻辑切换。
## 11.3 打击反馈事件包
| **反馈** | **轻击** | **重击 / 必杀** | **超必杀终结** |
|-------------|--------------|------------------------|--------------------------|
| **HitStop** | 46 Tick | 711 Tick | 1016 Tick |
| **火花** | 小型、短寿命 | 较大、方向性强 | 多层特效 + 屏幕闪光 |
| **音效** | 清脆 | 低频冲击 + 武器/元素层 | 专属终结音与低频冲击 |
| **震屏** | 02 px | 37 px | 8–14 px;可在设置中减弱 |
| **镜头** | 通常不变 | 轻微推近或冲击抖动 | 拉近、冻结、跟随终结动作 |
| **飘字** | 可选 | Counter / Punish 提示 | Super / KO 强调 |
## 11.4 镜头规则
- 基础镜头朝向战斗平面,目标点为两角色中点;距离随角色间距变化。
- 确保两人屏幕边缘留有安全边距,且舞台边界不会暴露未制作区域。
- 跳跃时相机只跟随一定比例的 Y 高度,避免频繁上下晃动。
- HitStop 期间可添加短促 Impulse,但相机位置插值需使用 PresentationTime。
- 超杀镜头必须有超时回退;角色被 KO、演出被中断或对象销毁时强制恢复基础镜头。
> **无障碍与舒适度**
>
> 设置中提供“震屏强度、闪光强度、手柄震动、动态镜头”开关。关闭这些效果不应改变 HitStop、输入、判定和比赛结果。
**ARCHITECTURE**
# 12 技术架构与更新顺序
```mermaid
flowchart TB
subgraph DATA["输入与数据"]
CD["Character / Move / Stage Data"]
IB["InputBuffer"] --> CR["CommandRecognizer"]
end
subgraph COMBAT["战斗域"]
BC["BattleClock<br/>固定 60 Tick"]
FC["FighterController<br/>StateMachine + Motor"]
MF["MatchFlow"]
MC["MoveController<br/>招式时间轴"]
CW["CollisionWorld<br/>Push / Hurt / Hit Box"]
HR["HitResolver<br/>统一命中结算"]
PS["ProjectileSystem"]
end
subgraph PRESENT["表现层"]
VA["VFX / Audio / 动画"]
CAM["CameraDirector"]
HUD["HUD / 菜单"]
end
CD --> FC
CD --> MC
CD --> PS
CR --> FC
BC --> FC
BC --> MF
FC --> MC
FC --> CW
MC --> CW
CW --> HR
HR --> FC
HR --> PS
PS --> CW
MF -.-> HUD
FC -.-> VA
FC -.-> CAM
FC -.-> HUD
HR -.-> VA
HR -.-> CAM
```
图 3 推荐的战斗域模块划分
## 12.1 核心模块
| **模块** | **职责** | **禁止事项** |
|-----------------------|------------------------------------------|--------------------------------|
| **BattleClock** | 固定 Tick、暂停、HitStop 域与帧步进 | 不读取玩家输入,不直接控制动画 |
| **InputService** | 设备采样、重绑定、写入 InputBuffer | 不决定招式,不改变角色状态 |
| **CommandRecognizer** | 匹配指令并生成动作请求 | 不扣资源,不直接播放动画 |
| **FighterController** | 聚合状态机、运动、生命、能量与动作实例 | 不直接搜索场景对象 |
| **MoveController** | 按 Tick 推进招式事件与取消窗口 | 不直接结算伤害 |
| **CollisionWorld** | 构建判定体、收集重叠候选 | 不处理格挡、伤害或 KO |
| **HitResolver** | 过滤、格挡、伤害、硬直、击退、资源与日志 | 不依赖特效对象是否存在 |
| **ProjectileSystem** | 生成、推进、回收飞行道具 | 不绕过 HitResolver |
| **MatchFlow** | 开场、计时、KO、回合与胜负 | 不持有角色招式细节 |
| **Presenter** | 动画、VFX、音效、镜头、HUD | 不反向决定战斗逻辑 |
## 12.2 每 Tick 更新顺序
> **1.** InputService 将设备状态汇总为 InputFrame,并写入每个玩家的 InputBuffer。
>
> **2.** BattleClock 判断全局暂停、超杀冻结与各实体 HitStop,确定本 Tick 谁可以推进。
>
> **3.** Fighter PreTick:识别指令、生成转移请求、处理已到期硬直。
>
> **4.** 状态机提交最高优先级转移;MoveController 推进当前招式帧并生成判定轨迹。
>
> **5.** FighterMotor 与 ProjectileSystem 计算位移;Stage/PushSolver 修正边界和角色重叠。
>
> **6.** CollisionWorld 重建本 Tick 的 Push/Hurt/Hit Box 并收集 HitCandidate。
>
> **7.** HitResolver 对全部候选排序和结算,写入生命、能量、硬直、击退与新状态请求。
>
> **8.** MatchFlow 检查 KO、时间结束与回合转换。
>
> **9.** Presenter 消费本 Tick 的只读快照与 PresentationEvent,更新动画、特效、音效、镜头和 HUD。
>
> **10.** CombatLog 记录输入摘要、状态摘要与命中结果,用于回放和问题复现。
**战斗主循环伪代码**
```csharp
void BattleTick() {
inputService.CaptureTickInputs();
battleClock.BeginTick();
foreach (var fighter in fighters) fighter.PreTick();
foreach (var fighter in fighters) fighter.CommitTransition();
foreach (var fighter in fighters) fighter.SimulateMoveAndMotor();
projectileSystem.Simulate();
collisionWorld.BuildSnapshot(fighters, projectiles);
hitResolver.Resolve(collisionWorld.CollectHitCandidates());
foreach (var fighter in fighters) fighter.PostTick();
matchFlow.EvaluateRound();
combatLog.RecordSnapshot();
presenter.PublishFrame();
}
```
## 12.3 事件分类
| **事件类型** | **是否可丢失** | **例子** |
|------------------------|-----------------|----------------------------------------|
| **Domain Command** | 不可 | 开始招式、扣能量、应用 HitResult |
| **Domain Event** | 不可 | FighterHit、RoundKO、ProjectileSpawned |
| **Presentation Event** | 可补播 / 可降级 | HitSpark、CameraShake、PlaySfx |
| **Telemetry Event** | 可批量 | 输入统计、帧耗时、招式使用率 |
**DATA**
# 13 数据配置与资源规范
## 13.1 CharacterData
| **字段组** | **示例字段** |
|--------------|----------------------------------------------------------|
| **身份** | CharacterId、显示名、阵营、默认皮肤 |
| **体型** | 身高、PushBox、站立/蹲姿 HurtBox 轨迹 |
| **移动** | 前走/后走速度、跳跃初速度、重力、落地硬直 |
| **资源** | 最大生命、最大能量、初始能量、受击能量倍率 |
| **动作映射** | Idle、Walk、Jump、Block、Hit、KO 与 MoveId 列表 |
| **表现** | AnimatorProfile、VFXProfile、AudioProfile、CameraProfile |
## 13.2 MoveData 核心字段
| **字段组** | **字段** | **说明** |
|------------|---------------------------------------|-------------------------------------------------------|
| **标识** | MoveId / DisplayName / Tags | 唯一 ID、编辑器名称与 Normal/Special/Super/Air 等标签 |
| **输入** | CommandId / Button / AllowedStates | 指令、攻击键、允许起招状态 |
| **时序** | Startup / ActiveSegments / Recovery | 全部使用整数 Tick |
| **命中** | Damage / HitLevel / HitStop / HitStun | 伤害、高低段、停顿与硬直 |
| **位移** | MotionCurve / Pushback / Launch | 攻击者位移、受击推远与浮空速度 |
| **判定** | HitboxTrack / HurtboxOverride | 逐 Tick 判定轨迹与姿态覆盖 |
| **防御** | BlockStun / Chip / GuardPush | 被格挡后的效果 |
| **资源** | MeterGain / MeterCost | 命中、格挡、挥空与使用成本 |
| **取消** | CancelWindows / CancelTargets | 时间区间、命中条件和目标标签 |
| **特殊** | Invuln / Armor / CounterHitBonus | 无敌、装甲、反击奖励 |
| **表现** | AnimationId / VFX / SFX / CameraCue | 只读消费的表现事件 |
**Unity 风格的数据对象示例**
```csharp
[CreateAssetMenu(menuName = "Fighting/Move Data")]
public sealed class MoveData : ScriptableObject {
public string moveId;
public MoveTag tags;
public CommandData command;
public int startupTicks;
public ActiveSegment[] activeSegments;
public int recoveryTicks;
public HitDefinition hit;
public HitboxTrack hitboxTrack;
public MotionTrack motionTrack;
public CancelWindow[] cancelWindows;
public InvulnerabilityWindow[] invulnerability;
public PresentationCue[] presentation;
}
```
## 13.3 资源目录建议
**建议的目录与归属**
```text
Assets/Game/
├── Battle/
│ ├── Core/ # Clock、状态机、命中、运动、回放
│ ├── Data/ # CharacterData、MoveData、StageData
│ ├── Editor/ # 帧表、判定轨迹与预览工具
│ └── Debug/ # Hitbox、输入、日志、帧步进
├── Characters/<CharacterId>/
│ ├── Animations/
│ ├── Moves/
│ ├── HitboxTracks/
│ ├── VFX/
│ ├── Audio/
│ └── Prefabs/
├── Stages/<StageId>/
├── UI/
└── Tests/
├── Unit/
├── Simulation/
└── PlayMode/
```
## 13.4 命名与版本
- 稳定 ID 使用小写蛇形:hero_01、st_lp、sp_projectile、su_finisher;显示名可本地化。
- 逻辑数据与表现资源分离:MoveData 不直接引用场景对象,只引用可加载资源 ID。
- 数据增加 schemaVersion;重大字段变更提供迁移脚本,而不是手工逐个修复。
- 所有平衡数值变更进入版本控制,并在提交说明中写明“旧值 → 新值 → 目的”。
- 角色 Prefab 只挂通用组件,不在 Prefab 上复制核心战斗脚本。
> **编辑器工具优先级**
>
> 最值得做的自定义工具是“招式时间轴 + HitBox/HurtBox 轨迹预览”。它应支持拖动 Tick、复制帧、镜像判定、显示动画参考姿态并即时运行单招测试。
**MATCH & UI**
# 14 UI、回合流程与设置
## 14.1 MatchFlow 状态
| **状态** | **持续 / 退出条件** | **允许内容** |
|-----------------|-------------------------|--------------------------------|
| **Loading** | 资源准备完成 | 不推进战斗 |
| **Intro** | 角色入场动画结束 | 镜头演出、不可操作 |
| **RoundReady** | “Round / Fight”演出结束 | 角色锁定、计时不动 |
| **Fighting** | KO 或时间归零 | 完整战斗逻辑 |
| **KOFreeze** | 短暂停顿结束 | 命中表现继续,禁止新输入 |
| **RoundResult** | 胜负演出完成 | 更新局数、播放胜利动作 |
| **MatchResult** | 玩家选择重开或退出 | 结果 UI |
| **Paused** | 关闭暂停 | BattleTime 停止,RealTime 继续 |
## 14.2 战斗 HUD
- 双方生命条:显示当前值、延迟损失值(白血)与 KO 状态。
- 双方能量条:0–100;满能量时有明确但不过度闪烁的提示。
- 回合标记:最多 2 个胜利点;当前回合和剩余时间居中。
- 连击与提示:Combo、Counter、Punish、Block;由 Domain Event 驱动。
- 训练/调试叠层:当前状态、MoveId、招式帧、帧优势、输入历史和判定框开关。
## 14.3 设置与可访问性
| **类别** | **设置项** |
|----------|---------------------------------------------------|
| **控制** | 键盘/手柄重绑定、摇杆死区、输入显示、简易指令开关 |
| **画面** | 分辨率、窗口模式、画质、动态模糊关闭、闪光强度 |
| **镜头** | 震屏强度、超杀镜头、镜头跟随强度 |
| **音频** | 总音量、音乐、音效、语音、手柄震动 |
| **游戏** | 回合数、时间、AI 难度、训练模式生命恢复 |
| **辅助** | 色盲友好 HUD、字幕、慢速训练、按键提示 |
> **UI 数据边界**
>
> HUD 只读取 BattleSnapshot,不直接持有 FighterController。这样暂停、回放、观战与未来联网时都可以复用同一套展示逻辑。
**AI & TRAINING**
# 15 AI 与训练木桩
## 15.1 MVP AI 结构
采用“感知 + 战术状态 + 效用评分”的轻量 AI。AI 不需要直接读取未来输入或命中结果;它只使用当前距离、双方状态、资源、角落位置和近期行为。决策间隔建议 4–8 Tick,并加入反应延迟。
| **战术状态** | **进入条件** | **候选行为** |
|--------------|-------------------------|--------------------------------------|
| **Neutral** | 双方可行动、距离中远 | 走位、能量弹、试探重脚、等待 |
| **Approach** | 距离过远或时间落后 | 前走、前跳、突进技 |
| **Pressure** | 对手在 BlockStun / 角落 | 轻攻击、延迟重击、必杀取消、后退诱骗 |
| **Defense** | 对手起攻或自身低血量 | 格挡、后退、对空、无敌技 |
| **Punish** | 检测到对手大收招 | 选择起手足够快且距离可达的招式 |
| **Combo** | 己方攻击命中确认 | 按预设连段脚本执行后续输入 |
## 15.2 难度差异
| **维度** | **简单** | **普通** | **困难** |
|--------------|----------------|------------------|------------------------|
| **反应延迟** | 1824 Tick | 1016 Tick | 610 Tick |
| **指令失误** | 较高 | 中等 | 低 |
| **格挡倾向** | 只格挡明显攻击 | 按距离与动作判断 | 能识别常见高低段 |
| **连段长度** | 12 击 | 34 击 | 4–6 击并使用资源 |
| **反制知识** | 无 | 有限对空/惩罚 | 基于帧差和距离选择惩罚 |
| **随机性** | 高 | 中 | 低但仍保留风格权重 |
## 15.3 训练木桩
- 站立、蹲下、跳跃、第一击后格挡、随机格挡。
- 受击后恢复生命、能量固定、位置重置。
- 录制 5–10 秒输入并循环播放,用于测试防守与惩罚。
- 显示连击伤害、起始伤害、缩放、帧优势和可行动 Tick。
- 一键重置到舞台中央或角落。
> **禁止“读心”**
>
> 困难 AI 可以更快、更准,但不应读取玩家尚未生效的输入,也不应在 0 Tick 内完美反应。可接受的优势来自更短反应延迟、更好的距离判断与更完整的连段脚本。
**PERFORMANCE & FUTURE**
# 16 性能、回放与联机预留
## 16.1 性能预算
| **项目** | **目标** |
|----------------|----------------------------------------------------------|
| **战斗 Tick** | 平均 \< 1.5 ms99 分位 \< 3 ms(双角色 + 常规飞行道具) |
| **碰撞判定体** | 每角色 HurtBox 48 个;单招 HitBox 14 个 |
| **运行时分配** | 战斗关键路径 0 B / Tick;列表和事件缓冲预分配 |
| **飞行道具** | 常规同时存在 ≤ 16;使用对象池 |
| **VFX / 飘字** | 对象池 + 最大并发;超限时降级而非阻塞 |
| **动画** | 避免每 Tick 字符串查找;缓存哈希与状态 ID |
## 16.2 回放
首版回放只需保存初始随机种子、角色/场景数据版本与每 Tick 的 InputFrame。回放时重新运行战斗逻辑,并周期性记录状态哈希。若哈希不一致,立即输出首个分歧 Tick、角色状态、位置、生命与当前招式。
- 回放文件不保存动画、特效或音频状态。
- 每 60 Tick 记录一次轻量状态哈希,用于自动检测非确定性。
- 版本不兼容时明确拒绝播放,不尝试静默修复。
- Bug 报告可自动附带最近 10 秒输入与 CombatLog。
## 16.3 回滚联机预留
MVP 不实现联网,但核心域应避免阻断未来回滚:战斗逻辑固定 Tick、输入驱动、状态可序列化、表现层可重建。真正接入网络时,需进一步处理浮点确定性、快照大小、回滚重演性能与输入延迟。
| **现在就做** | **以后再做** |
|---------------------------------------|------------------------------|
| 固定 Tick、输入帧、战斗快照、状态哈希 | 网络传输、预测输入、回滚窗口 |
| 战斗域不依赖场景查找与动画事件 | 跨平台确定性与浮点策略 |
| 表现事件带唯一 ID,允许回滚撤销/去重 | 观战、断线重连、匹配与反作弊 |
| 对象池和可重建飞行道具 | 网络带宽压缩与同步协议 |
> **现实边界**
>
> 不要为了“以后可能联网”过早引入复杂框架。只要保持固定 Tick、输入驱动、数据可序列化和表现解耦,单机原型就已经保留了最有价值的联机基础。
**DEBUGGING**
# 17 调试工具与可观测性
## 17.1 必做工具
| **工具** | **功能** | **验收标准** |
|-------------------|--------------------------------------|--------------------------------|
| **帧步进** | 暂停后每次推进 1 Tick / 10 Tick | 状态、动画采样和判定体同步推进 |
| **输入历史** | 显示最近 30–60 Tick 的方向和按键 | 标出已消费输入与指令匹配区间 |
| **判定框显示** | Hit/Hurt/Push Box 颜色区分 | 镜像、缩放和移动后仍准确 |
| **招式面板** | MoveId、当前帧、阶段、取消窗口 | 能看到有效 HitBox 与无敌窗口 |
| **战斗日志** | 命中候选、过滤原因、HitResult | 可按角色、招式与 Tick 筛选 |
| **状态快照** | 位置、速度、状态、生命、能量、Facing | 一键复制为文本用于 Bug 单 |
| **输入录制/回放** | 录制并重复执行短序列 | 多次播放结果哈希一致 |
## 17.2 CombatLog 示例
**命中日志应能回答“为什么发生这个结果”**
```text
T=1842 P1 move=st_hp frame=8 phase=Active
candidate: hitbox=body_0 target=P2 hurtbox=torso
guardIntent=true stance=Standing hitLevel=Mid => BLOCK
result: blockStun=14 hitStop=8 guardPush=(0.42,0)
meter: P1 +4, P2 +2
transition: P2 -> BlockStun(14), P1 stays st_hp frame=8
```
## 17.3 自动监控断言
- 角色生命、能量与状态枚举始终在合法范围。
- 同一 Fighter 同 Tick 只能提交一个最终状态转移。
- MoveController 帧不得超出总帧数;已结束招式必须释放 MoveInstance。
- 同一 HitGroup 不得在禁止重击间隔内重复命中同一目标。
- KO 后不得接受玩家输入或生成新的攻击 HitBox。
- 角色逻辑位置不得离开舞台边界,Z 逻辑坐标必须为 0。
- 回放状态哈希不一致时自动中止并导出差异。
> **调试不是“开发者模式装饰”**
>
> 格斗游戏的大多数问题都发生在特定 Tick 和特定状态组合。没有输入历史、帧步进和判定框,团队会把时间花在猜测而不是定位。
**DELIVERY PLAN**
# 18 开发里程碑与任务拆分
以下计划以 1 名程序 + 1 名通才美术/动画的原型团队为参考。若是个人开发,可按同一顺序推进,但不要并行制作大量内容。每个阶段必须通过验收门再进入下一阶段。
| **阶段** | **主要交付** | **验收门** |
|-------------------|-------------------------------------------------|--------------------------------------------------|
| **M0 工程骨架** | BattleClock、输入帧、基础数据、空场景、调试面板 | 帧步进与输入历史可用;固定 Tick 不受渲染帧率影响 |
| **M1 运动原型** | 双角色生成、行走、转身、跳跃、PushBox、镜头 | 无穿透、无越界;30/60/120 FPS 手感一致 |
| **M2 命中闭环** | 普通技、Hit/Hurt Box、HitStop、受击、格挡、KO | 镜像角色能完成一局;结果可由 CombatLog 解释 |
| **M3 招式系统** | 指令识别、取消、飞行道具、对空、突进、超杀 | 录制输入可稳定触发;资源和多段命中正确 |
| **M4 比赛产品化** | HUD、回合流程、暂停、设置、本地双人、训练木桩 | 从启动到重开无阻断;关键设置可保存 |
| **M5 AI 与打磨** | AI、VFX/SFX、镜头、两角色内容、性能优化 | 完整 Demo 可连续游玩 30 分钟无卡死或明显漏判 |
| **M6 发布准备** | 测试回归、手柄覆盖、打包、日志与崩溃信息 | 验收清单全绿;已知问题有明确说明 |
## 18.1 工作量粗估
| **模块** | **人日范围** | **备注** |
|--------------------------|--------------|-----------------------------------------------------|
| **战斗核心与调试** | 8–12 | 输入、时钟、状态机、运动、判定、命中与工具 |
| **普通技 / 必杀 / 超杀** | 5–8 | 不含高质量动画制作 |
| **比赛流程与 UI** | 35 | 基础 HUD、设置、回合与暂停 |
| **AI 与训练模式** | 3–5 | 简单效用 AI + 训练木桩 |
| **表现整合** | 5–8 | 动画接入、特效、音效、镜头与反馈 |
| **测试与优化** | 4–7 | 自动测试、性能、手柄、打包与回归 |
| **合计** | 28–45 | 占位素材的功能型 Demo;个人开发按技能和素材情况浮动 |
## 18.2 推荐任务拆分
- 每个功能任务都包含:数据、运行时、调试显示、测试场景与验收用例。
- 角色动作与判定由同一 MoveId 串联,避免动画名、招式名和代码枚举不一致。
- 每新增一个招式,必须同时提交帧表、HitboxTrack、命中/格挡结果和训练模式验证步骤。
- 每次调整核心结算顺序,都运行固定回放集并比较状态哈希。
- 表现任务在战斗事件稳定后接入,不直接修改战斗核心以“配合动画”。
> **第一可玩顺序**
>
> Idle → Walk → Jump → 一个普通技 → HitBox/HurtBox → HitStop/HitStun → Block → KO。完成这条链路前,不做超杀镜头、AI 或复杂 UI。
**QA**
# 19 测试方案与验收标准
## 19.1 自动测试层级
| **层级** | **覆盖内容** | **示例** |
|-------------------|-----------------|-----------------------------------------------|
| **Unit** | 纯算法与数据 | 指令匹配、伤害缩放、格挡段位、优先级排序 |
| **Simulation** | 无渲染战斗 Tick | 固定输入运行 600 Tick,检查状态哈希与最终生命 |
| **PlayMode** | 场景与组件集成 | 跳跃接地、舞台边界、飞行道具回收、HUD 更新 |
| **Golden Replay** | 回归回放集 | 10–30 条已知战斗录像在每次构建中重放 |
| **Manual** | 手感与设备 | 键盘/多种手柄、帧率、震屏、视觉可读性 |
## 19.2 核心验收用例
| **ID** | **场景** | **通过标准** |
|------------|-------------------------------|------------------------------------------|
| **MOV-01** | 前后行走并互相推挤 | 不穿透、不抖动、不越界;角落分摊正确 |
| **MOV-02** | 30/60/120 FPS 下连续跳跃 | 起跳高度、滞空 Tick 与落点一致 |
| **INP-01** | 快速输入 236+P | 在宽容窗口内稳定触发,超窗不触发 |
| **INP-02** | 236236+P 且能量不足 | 不吞键;按优先级回退到合法动作 |
| **ATK-01** | 轻拳命中站立对手 | 伤害、HitStop、HitStun、推远与特效一致 |
| **BLK-01** | 站防高/中/低段 | 高/中成功,低段失败并进入受击 |
| **BLK-02** | 蹲防高/中/低段 | 中/低成功,高段失败并进入受击 |
| **HIT-01** | 双方同 Tick 普通攻击 | 按交易规则双方受击,日志顺序稳定 |
| **HIT-02** | 多 HurtBox 与一个 HitBox 重叠 | 只结算一次,命中点选择一致 |
| **SP-01** | 飞行道具命中/格挡/出界 | 三种路径均正确回收且无重复命中 |
| **SP-02** | 对空技无敌窗口 | 窗口内忽略指定攻击,窗口外正常受击 |
| **SU-01** | 满能量超杀 | 只扣一次资源;冻结、镜头、多段与终结正确 |
| **KO-01** | 同 Tick 生命归零与多段后续 | 只结算合法段;进入 KO 后无新攻击 |
| **REP-01** | 同输入回放 20 次 | 最终状态与中间哈希完全一致 |
## 19.3 功能完成定义(Definition of Done
- 设计数据已填写且通过合法性校验,没有魔法数字散落在运行时代码。
- 功能可在 Debug HUD 中观察关键状态与 Tick。
- 至少有 1 个自动测试或固定回放覆盖主要逻辑。
- 键盘与至少一种手柄可用,重绑定后仍正常。
- 30/60/120 FPS 下结果一致;暂停、慢动作与 HitStop 不影响输入匹配。
- 不存在已知的状态卡死、重复命中、越界、资源重复扣除或 KO 后继续行动。
- 表现层缺失时战斗逻辑仍可完整运行;表现对象销毁不会破坏比赛。
> **发布门槛**
>
> 完整对战连续运行 30 分钟,无崩溃、无永久卡死、无明显输入丢失;核心回放集全部通过;关键路径战斗 Tick 在目标机器上满足性能预算。
**RISKS & APPENDIX**
# 20 风险、原创边界与附录
## 20.1 主要风险与缓解
| **风险** | **表现** | **缓解措施** |
|------------------|------------------------------------------|------------------------------------------|
| **动画驱动逻辑** | 判定漏发、过渡不同步、改动画导致规则变化 | 逻辑帧表权威;动画只采样与展示 |
| **范围持续膨胀** | 投技、防反、联网、角色内容同时开工 | 严格按 M0–M6 验收门推进 |
| **输入手感差** | 指令过严或误触发,玩家无法稳定出招 | 输入录制、匹配日志、可配置宽容窗口 |
| **判定难调** | 动画好看但判定不稳定或不可读 | 独立 HitboxTrack 编辑器与帧步进 |
| **碰撞不确定** | 动态刚体、回调顺序导致同帧结果变化 | 运动学控制 + 收集后统一结算 |
| **表现反向侵入** | 镜头/特效脚本改生命或状态 | Domain / Presentation 事件边界与代码审查 |
| **内容制作成本** | 每个招式需要动作、判定、特效、音效 | 先做少量高辨识度招式,复用事件模板 |
| **知识产权风险** | 造型、动作、招式名和 UI 过度相似 | 建立原创设定与视觉语言;保留素材来源记录 |
## 20.2 原创边界检查
- 不要直接使用现有格斗游戏的角色姓名、服装轮廓、招式名称、语音、UI、标志或特效图样。
- 通用机制如走、跳、格挡、飞行道具、对空、能量槽和超杀冻结可以采用,但表达方式应原创。
- 动作捕捉、音效、字体、模型与特效包需确认商业许可范围,并保存许可证与购买凭证。
- 宣传文案使用“2.5D 对战格斗”描述,不以他人商标作为产品名称或核心卖点。
## 附录 A:首个灰盒角色帧表示例
| **招式** | **输入** | **起/持/收** | **伤害** | **硬直 H/B** | **用途** |
|--------------|----------|------------------|----------|--------------|----------------------------|
| **站轻拳** | LP | 4 / 2 / 8 | 40 | 10 / 7 | 近身确认;命中可取消必杀 |
| **站重拳** | HP | 9 / 3 / 18 | 90 | 16 / 12 | 重击;部分帧可对空 |
| **站轻脚** | LK | 5 / 3 / 10 | 45 | 11 / 8 | 中距离试探 |
| **站重脚** | HK | 11 / 3 / 22 | 105 | 18 / 14 | 长距离;反击风险高 |
| **蹲轻脚** | 2+LK | 5 / 2 / 9 | 35 | 9 / 7 | 低段;可链轻拳 |
| **跳重脚** | 空中 HK | 7 / 5 / 着地6 | 80 | 14 / 11 | 跳入攻击 |
| **能量弹** | 236+P | 12 / 投射物 / 22 | 80 | 15 / 12 | 远程牵制;削血 8 |
| **对空升击** | 623+P | 5 / 6 / 28 | 110 | 击倒 / 15 | 16 Tick 上半身无敌 |
| **突进踢** | 214+K | 10 / 5 / 20 | 100 | 17 / 13 | 接近与连段收尾 |
| **超必杀** | 236236+P | 7 / 多段 / 35 | 300 | 击倒 / 20 | 消耗 100;起手冻结 10 Tick |
*H/B = HitStun / BlockStun。所有数值仅为原型起点,不代表最终平衡。*
## 附录 B:首轮实现清单
| **完成** | **任务** | **完成** | **任务** |
|----------|----------------------------------------|----------|----------------------------------------------|
| □ | BattleClock 与 60 Tick 主循环 | □ | InputBuffer 与方向相对化 |
| □ | CommandRecognizer 与输入日志 | □ | FighterStateMachine 与转移优先级 |
| □ | FighterMotor、跳跃、舞台边界与 PushBox | □ | MoveData、MoveTimeline 与取消窗口 |
| □ | HitBox/HurtBox 轨迹与调试显示 | □ | HitResolver、格挡、伤害、HitStop、硬直与击退 |
| □ | 飞行道具、对空技、突进技与超必杀 | □ | MatchFlow、HUD、KO、暂停与重开 |
| □ | 训练木桩、AI、输入回放与状态哈希 | □ | 动画、VFX、SFX、镜头与可访问性设置 |
## 附录 C:项目启动时的 10 个决定
> **1.** 确认战斗是严格 2D 平面,还是允许 Z 轴闪避;本方案默认严格 2D。
>
> **2.** 确认普通技数量与按钮数;本方案默认 4 攻击键。
>
> **3.** 确认格挡采用背向方向,是否提供独立 Guard 辅助键。
>
> **4.** 确认是否支持蹲姿与高低段;本方案建议首版支持。
>
> **5.** 确认每角色必杀技与超杀数量;本方案为 3 + 1。
>
> **6.** 确认是否有动态刚体需求;战斗角色默认不使用动态刚体。
>
> **7.** 确认首版仅单机/本地对战,不在 MVP 中实现联网。
>
> **8.** 确认动画与模型来源、许可和可用动作数量。
>
> **9.** 确认调试工具必须随核心功能同步交付。
>
> **10.** 确认第一可玩验收后再投入完整美术与角色内容。
> **最终建议**
>
> 先做一个角色镜像对战,完整打通“一次输入 → 一个动作 → 一个判定 → 一次命中/格挡 → 一次状态恢复 → 一次 KO”。这条链路稳定后,新增角色与招式才会变成可控的内容生产,而不是继续堆技术债。