70 KiB
横版 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 | 便于用整数表达伤害与缩放 |
| 超必杀能量 | 0–100 | 命中、格挡与受击均可按招式配置增长 |
| 时间结束 | 生命百分比高者胜 | 相同则判平局并重开该回合 |
| 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,超必杀 20–24 Tick,按键缓冲 4–6 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 |
指令识别伪代码(方向相对角色朝向)
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,子状态负责行走、跳跃、攻击阶段和受击类型。状态机只处理“角色当前允许做什么”,招式帧表负责“某个动作在第几帧发生什么”。
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 状态接口
状态机接口建议
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 建议 3–4 Tick,期间可被命中。
-
起跳方向在 JumpStart 结束时锁定;垂直跳 X 速度为 0,前后跳使用各自速度。
-
空中不允许再次跳跃;是否允许空中格挡、空中必杀应由角色与招式数据显式配置。
-
接地判定使用脚底 Probe 与上一 Tick 高度,避免高速下落穿透地面。
-
被击飞时使用 ReactionVelocity,不复用普通跳跃状态,以便独立控制重力、弹地和受身。
角色运动 Tick 伪代码
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 | 高伤害 / 对空 | 8–10 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 给出;轻攻击 6–9 Tick,重攻击 12–18 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。
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 数据
统一命中结果对象
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 能量系统
| 事件 | 攻击者获得 | 防守者获得 |
|---|---|---|
| 普通技命中 | 2–5 | 1–3 |
| 普通技被格挡 | 1–3 | 1–2 |
| 必杀技命中 | 5–10 | 3–5 |
| 必杀技被格挡 | 3–6 | 2–4 |
| 受到重击 | — | 5–8 |
| 使用超必杀 | 消耗 100 | — |
能量增长应全部来自 MoveData,不写死在攻击类型分支中。
10.3 超必杀执行流程
1. CommandRecognizer 检测到超必杀指令,并确认当前状态允许、能量为 100。
2. 立即预占资源并创建 SuperMoveInstance,防止同 Tick 重复触发。
3. 进入 8–15 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 | 4–6 Tick | 7–11 Tick | 10–16 Tick |
| 火花 | 小型、短寿命 | 较大、方向性强 | 多层特效 + 屏幕闪光 |
| 音效 | 清脆 | 低频冲击 + 武器/元素层 | 专属终结音与低频冲击 |
| 震屏 | 0–2 px | 3–7 px | 8–14 px;可在设置中减弱 |
| 镜头 | 通常不变 | 轻微推近或冲击抖动 | 拉近、冻结、跟随终结动作 |
| 飘字 | 可选 | Counter / Punish 提示 | Super / KO 强调 |
11.4 镜头规则
-
基础镜头朝向战斗平面,目标点为两角色中点;距离随角色间距变化。
-
确保两人屏幕边缘留有安全边距,且舞台边界不会暴露未制作区域。
-
跳跃时相机只跟随一定比例的 Y 高度,避免频繁上下晃动。
-
HitStop 期间可添加短促 Impulse,但相机位置插值需使用 PresentationTime。
-
超杀镜头必须有超时回退;角色被 KO、演出被中断或对象销毁时强制恢复基础镜头。
无障碍与舒适度
设置中提供“震屏强度、闪光强度、手柄震动、动态镜头”开关。关闭这些效果不应改变 HitStop、输入、判定和比赛结果。
ARCHITECTURE
12 技术架构与更新顺序
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 记录输入摘要、状态摘要与命中结果,用于回放和问题复现。
战斗主循环伪代码
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 风格的数据对象示例
[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 资源目录建议
建议的目录与归属
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 难度差异
| 维度 | 简单 | 普通 | 困难 |
|---|---|---|---|
| 反应延迟 | 18–24 Tick | 10–16 Tick | 6–10 Tick |
| 指令失误 | 较高 | 中等 | 低 |
| 格挡倾向 | 只格挡明显攻击 | 按距离与动作判断 | 能识别常见高低段 |
| 连段长度 | 1–2 击 | 3–4 击 | 4–6 击并使用资源 |
| 反制知识 | 无 | 有限对空/惩罚 | 基于帧差和距离选择惩罚 |
| 随机性 | 高 | 中 | 低但仍保留风格权重 |
15.3 训练木桩
-
站立、蹲下、跳跃、第一击后格挡、随机格挡。
-
受击后恢复生命、能量固定、位置重置。
-
录制 5–10 秒输入并循环播放,用于测试防守与惩罚。
-
显示连击伤害、起始伤害、缩放、帧优势和可行动 Tick。
-
一键重置到舞台中央或角落。
禁止“读心”
困难 AI 可以更快、更准,但不应读取玩家尚未生效的输入,也不应在 0 Tick 内完美反应。可接受的优势来自更短反应延迟、更好的距离判断与更完整的连段脚本。
PERFORMANCE & FUTURE
16 性能、回放与联机预留
16.1 性能预算
| 项目 | 目标 |
|---|---|
| 战斗 Tick | 平均 < 1.5 ms,99 分位 < 3 ms(双角色 + 常规飞行道具) |
| 碰撞判定体 | 每角色 HurtBox 4–8 个;单招 HitBox 1–4 个 |
| 运行时分配 | 战斗关键路径 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 示例
命中日志应能回答“为什么发生这个结果”
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 | 3–5 | 基础 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 | 1–6 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”。这条链路稳定后,新增角色与招式才会变成可控的内容生产,而不是继续堆技术债。