PROJECT-v M3:完整战斗闭环实现拆解

M3 的目标不是把战斗“做得热闹”,而是把 M2 的基础攻击、受伤、死亡链路扩展成可继续承载动作游戏手感的完整战斗骨架:玩家能闪避,攻击能按命中结果取消,命中反馈能从战斗事实触发,技能和武器能通过配置资产接入,测试场景和 runtime probe 能证明这条链路在 Unity 工程里真实可运行。

除注明 docs 仓库的文档外,本文所有工程路径均以 PROJECT-V 项目根目录为基准;docs 路径均以 PROJECT-V-game-docs 根目录为基准。

关联提交和依据

M3 功能主体提交:

commit 用途
e5317f8 feat(combat): complete M3 full combat milestone,完整战斗里程碑实现

分支状态:

分支 说明
develop M3 实施分支
origin/develop 已推送,范围 5d0e869..e5317f8

主要参考产物:

类型 路径
交付报告 reports/M3_delivery_report.html
QA 报告 qa/reports/M3_test_report.md
EditMode 结果 qa/results/M3_EditMode_TestResults.xml
PlayMode 结果 qa/results/M3_PlayMode_TestResults.xml
30s Runtime Probe qa/results/M3_RuntimeProbe.json
60s Runtime Probe qa/results/M3_RuntimeProbe_60s.json
M3 Feature Spec,docs 仓库 design/feature_specs/M3_combat_full.md
武器修饰规则,docs 仓库 design/weapon_worldview_modifiers.md
Sprint 状态,docs 仓库 project/sprints/SPRINT_03.md
Project State,docs 仓库 project/PROJECT_STATE.md

M3 的目标和边界

M3 承接 M2 的最小战斗闭环,但不重写 M2 的攻击、生命、敌人和事件基础。它的范围是把“能打、能受伤、能死”扩展成“能通过战斗状态做动作决策”。

M3 纳入实现的内容:

  • 闪避系统:无敌帧、位移、冷却、SFX 和事件。

  • 攻击取消:轻攻击命中后可转重攻击或闪避,重攻击后段可转闪避。

  • 连招倍率:轻攻击链、重击终结倍率和输入缓冲。

  • 命中反馈:hitstop、相机震动、闪白、粒子、伤害数字和 SFX hook。

  • 技能系统:U/I 两个激活槽、O 预留槽、8 个内功/轻功/暗器技能。

  • 武器修饰:8 种冷兵器 × 3 个异世界形态,共 24 个 form。

  • 15 个 placeholder WAV,用于把音频调用链先接通。

  • M3_FullCombat.unity 白盒战斗测试场景。

  • M3 setup、EditMode、PlayMode、Windows Development Build 和 runtime probe 验证。

M3 明确不把下面内容当成完成标准:

  • 正式技能 HUD 和完整 UI 表现。

  • 最终混音、正式技能特效和正式粒子资源。

  • 正式 projectile 物理表现;当前暗器类技能仍是白盒化命中实现。

  • Boss、镜像 Boss、手工关卡流程和 Roguelite Build。

  • 30 分钟 1080p soak;M3 的 30s/60s probe 只是阶段工程验证,不等同于 release-grade QA gate。

这个边界是必要的。M3 如果同时做 Boss、正式 UI、正式音频和关卡,会把战斗状态链、表现层和内容设计混在一起,问题定位会失控。当前阶段真正需要固定的是战斗因果链。

工程生成入口

M3 的落地入口是 unity-project/Assets/_Project/Editor/M3ProjectBuilder.cs

SetupM3() 的第一步是调用 M2 setup,确保 M3 是在 M2 战斗闭环上增量构建,而不是另起一套战斗框架。之后它负责生成或更新:

类别 关键路径
闪避配置 unity-project/Assets/_Project/Player/SO/Dodge_M3.asset
技能资产 unity-project/Assets/_Project/Player/SO/Skills/
武器资产 unity-project/Assets/_Project/Player/SO/Weapons/
M3 音频占位 unity-project/Assets/_Project/Audio/SFX/M3/
M3 测试场景 unity-project/Assets/Scenes/TestScenes/M3_FullCombat.unity
Runtime Probe unity-project/Assets/_Project/Player/Scripts/M3RuntimeProbe.cs

VerifyM3Setup() 则做硬性检查:

  • 闪避配置必须是 0.3s 无敌、3m 位移、0.6s 冷却。

  • 技能资产必须正好 8 个。

  • 武器配置必须正好 8 个。

  • 武器世界观修饰必须正好 24 个。

  • M3 placeholder SFX 至少 15 个。

  • Player Prefab、输入绑定、M3 场景和 scene harness 必须存在。

这里的工程决策很清楚:M3 不依赖一次手工搭好的 Unity 场景。配置、Prefab 接线、输入、场景和验收入口都能被同一个 Editor tooling 重建和校验。

闪避系统

闪避由两个核心对象组成:

文件 职责
unity-project/Assets/_Project/Player/Scripts/DodgeConfigSO.cs 保存闪避参数和音效数组
unity-project/Assets/_Project/Player/Scripts/PlayerDodge.cs 消费输入、位移、无敌、冷却和事件发布

M3 默认参数:

参数
无敌时间 0.3s
位移距离 3m
位移时长 0.3s
冷却 0.6s
SFX dodge_whoosh_01/02/03

PlayerDodge.TryStartDodge() 的实现重点不是“播放一个动作”,而是同时处理战斗语义:

  1. 死亡或冷却中不能闪避。

  2. 输入方向为空时,使用角色朝向的反方向作为 fallback。

  3. 根据 distance / durationSeconds 计算闪避速度。

  4. 调用 HealthComponent.GrantInvulnerability() 写入无敌时间。

  5. 播放随机闪避 SFX。

  6. 发布 OnPlayerDodge 事件。

这让闪避在 M3 里不是单纯位移,而是战斗状态的一部分:它能避伤害、能被测试探针观察,也能被后续表现层订阅。

攻击取消和连招

M3 没有引入新的攻击框架,而是在 M2 的 PlayerAttack 上扩展状态规则。这个选择是正确的:M2 已经把输入、AttackConfigSO、命中框、HealthComponent 和事件链跑通,M3 应该复用这条链,而不是为了“完整战斗”重写一套更复杂的动作系统。

关键代码位于:

  • unity-project/Assets/_Project/Player/Scripts/PlayerAttack.cs

  • unity-project/Assets/_Project/Player/Scripts/PlayerCombo.cs

取消规则:

当前动作 条件 可取消到
轻攻击 已命中目标 重攻击
轻攻击 已命中目标 闪避
轻攻击 whiff,未命中 不允许取消
重攻击 进入最后 30% recovery 闪避

PlayerAttack 中的关键状态是:

1
2
3
4
5
6
7
currentAttack
attackTimer
bufferedAttackType
bufferedAttackTimer
hasLandedHit
currentDamageMultiplier
nextAttackDamageMultiplier

轻转重的判断依赖 hasLandedHit,这能把“命中奖励”与“空挥惩罚”区分开。空挥时输入不会立刻取消当前动作,只会进入输入缓冲;当前攻击结束后再消费。

连招由 PlayerCombo 管:

参数
轻攻击最大段数 3
输入缓冲 0.2s
连招重置窗口 0.8s
每段轻攻击加成 +10%
三段后重击终结倍率 1.35x

最终伤害倍率在 PlayerAttack.StartAttack() 中合成:

1
comboMultiplier * nextAttackDamageMultiplier * WeaponDamageMultiplier

这个设计把三类来源分开了:

  • 连招倍率来自 PlayerCombo

  • 技能下一击倍率来自 PlayerSkillController 写入的 nextAttackDamageMultiplier

  • 武器倍率来自 PlayerWeaponController

这比把所有倍率塞进攻击配置更干净,因为攻击本身只定义基础招式,运行时构成由连招、技能和武器共同决定。

命中反馈链

M3 的反馈链不是装饰层强行播放效果,而是从命中事实触发。

实际链路:

1
2
3
4
5
6
7
8
PlayerAttack.ApplyHitbox()
-> Hitbox2D.Overlap()
-> HealthComponent.TakeDamage()
-> HitFeedback.PlayHitFeedback()
-> ApplyKnockback()
-> PlayHitstop()
-> CameraShake.Main.Shake()
-> OnAttackHit

涉及文件:

文件 职责
unity-project/Assets/_Project/Combat/Scripts/HitFeedback.cs 闪白、粒子、伤害数字
unity-project/Assets/_Project/Player/Scripts/CameraShake.cs 相机震动和 rumble SFX
unity-project/Assets/_Project/Player/Scripts/PlayerAttack.cs 命中后触发 feedback、hitstop、shake 和事件

轻攻击和重攻击的反馈参数也被写回攻击配置:

攻击 hitstop 相机震动
Light 6 frames 0.05
Heavy 12 frames 0.10

HitFeedback 当前会生成临时 HitParticleDamageNumber 对象,并记录最后一次伤害数字和暴击状态,方便测试验证。它不是最终表现资产,但已经把表现触发点放在正确位置:有效伤害发生之后,而不是输入按下之后。

技能系统

技能系统由三层组成:

文件 职责
unity-project/Assets/_Project/Player/Scripts/SkillSlot.cs 定义 U/I/O 槽位
unity-project/Assets/_Project/Player/Scripts/SkillSO.cs 配置技能类别、冷却、效果参数和 SFX
unity-project/Assets/_Project/Player/Scripts/PlayerSkillController.cs 消费输入、执行效果、管理冷却、发布事件

M3 实装 U/I 两个槽,O 作为预留槽保留在输入和结构中。8 个主动技能如下:

技能 槽位 类别 效果
juqi U Internal 下一击 2.5x 伤害,窗口 5s
huti U Internal 60 点护盾,持续 2s
zhiyu U Internal 回复 35 HP
jinzhongzhao U Internal 无敌 1.5s
shuangbu I Lightness 位移 5m,无敌 0.4s,冷却 3s
feizhen I HiddenWeapon 3 枚飞针,每枚 8 伤害
guiyingbu I Lightness 隐匿 1.5s
feidao I HiddenWeapon 8 向飞刀,每枚 6 伤害

技能效果不是硬写在输入层,而是通过 SkillEffectType 分发:

  • NextAttackDamageMultiplier

  • DamageShield

  • Heal

  • Invulnerability

  • Dash

  • ProjectileBurst

  • Concealment

这保证了输入槽位、技能资产和技能效果之间保持松耦合。后续 M4/M5 可以替换技能装配逻辑或 UI,而不必把 U/I/O 键写死进每个效果分支。

当前暗器类技能仍是白盒实现:在范围内找最近敌人,把 projectile 数量和单枚伤害合并成一次伤害应用。这对 M3 验收足够,但不是正式 projectile 系统。

武器和异世界修饰

武器系统的核心不在“做 24 把武器”,而在“同一把冷兵器能被世界观层修饰”。

涉及文件:

文件 职责
unity-project/Assets/_Project/Player/Scripts/WeaponConfigSO.cs 定义武器类型和世界观修饰数组
unity-project/Assets/_Project/Player/Scripts/PlayerWeaponController.cs 应用当前武器和当前世界观修饰

M3 覆盖 8 种武器:

  • Sword

  • Dao

  • Spear

  • Dagger

  • Staff

  • Hammer

  • Flexible

  • DualShortBlades

每种武器有 3 个世界观 form:

世界观 视觉 tint
Wasteland #CC6633
Cyberpunk #22D3EE
Biohazard #84CC16

所有 form 当前的 damageMultiplier 统一为 1.2,不同武器通过 rangeMultiplier 拉开基础差异,例如 Spear 和 Staff 是 1.1,Flexible 是 1.15,Dagger 和 DualShortBlades 是 0.95

PlayerWeaponController.SetWorldview() 的作用是切换当前修饰,并更新:

  • 伤害倍率。

  • 攻击范围倍率。

  • 视觉 tint。

  • OnWeaponModifierChanged 事件。

M3 场景中使用默认武器接线来验证倍率,Player Prefab 本身不应该被某个测试场景的具体武器选择锁死。这个决策能避免后续关卡、掉落和 Build 系统接入时反复改基础 Prefab。

音频占位

M3 生成了 15 个 placeholder WAV,覆盖:

  • 3 个闪避 whoosh。

  • 轻击、重击和暴击命中。

  • 8 个技能激活音效。

  • 1 个 camera rumble。

这些文件位于 unity-project/Assets/_Project/Audio/SFX/M3/。它们的价值不是音质,而是把音频 hook 放进正确位置:闪避、挥击、命中、技能和震屏都已经能触发音频调用。正式混音和替换资产应留到音频生产阶段。

M3 测试场景

M3 测试场景是 unity-project/Assets/Scenes/TestScenes/M3_FullCombat.unity

这个场景的角色不是“关卡体验”,而是白盒 harness:

  • 放置玩家和 3 个敌人。

  • 挂接 M3 dodge、skills、weapon、feedback 和 runtime probe。

  • 让 automated probe 能在固定时间窗口内触发闪避、U 技能、I 技能和武器世界观切换。

  • 让 EditMode / PlayMode 可以检查 M3 系统是否真实挂进 Unity 场景。

这仍然是测试场景,不是正式关卡。M4 才应该把 M3 战斗链放进手工关卡、Boss 和镜像 Boss 的设计环境里验证。

验证结果

M3 当前验证结果如下:

验证项 证据 结果
M3 setup generation ProjectV.EditorTools.M3ProjectBuilder.SetupM3 Passed
M3 setup verification ProjectV.EditorTools.M3ProjectBuilder.VerifyM3Setup Passed
EditMode qa/results/M3_EditMode_TestResults.xml 20 / 20 passed
PlayMode qa/results/M3_PlayMode_TestResults.xml 10 / 10 passed
Windows Development Build unity-project/Builds/Windows/PROJECT-V.exe Success,构建产物被 gitignore 排除
Runtime Probe 30s qa/results/M3_RuntimeProbe.json Avg 60.008 FPS,m3SystemsReady: true
Runtime Probe 60s qa/results/M3_RuntimeProbe_60s.json Avg 59.999 FPS,frameCount: 3600m3SystemsReady: true

60s probe 的关键结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"warmupSeconds": 3,
"totalElapsedSeconds": 63,
"measuredSeconds": 60.001,
"frameCount": 3600,
"averageFps": 59.999,
"minFps": 48.154,
"maxFps": 146.23,
"targetFrameRate": 60,
"m3SystemsReady": true,
"dodgeStarted": true,
"skillUActivated": true,
"skillIActivated": true,
"weaponDamageMultiplier": 1.2,
"enemyCount": 3,
"playerHp": 64,
"playerIsDead": false
}

这个结果说明 runtime probe 不只是空跑场景。它实际确认了:

  • M3 系统挂接完成。

  • 闪避成功开始。

  • U 槽技能成功激活。

  • I 槽技能成功激活。

  • 武器世界观切换后伤害倍率读到 1.2

  • 3 个敌人存在。

  • 玩家在 60s probe 后仍存活。

EditMode 覆盖了配置、输入、Prefab、场景、技能资产、武器资产和 24 个世界观 form。PlayMode 覆盖了闪避无敌和冷却、命中反馈链、聚气下一击伤害、轻攻击命中取消、空挥不能取消、projectile / concealment 技能效果和武器修饰倍率。

已知风险

M3 已通过阶段验收,但还有明确风险:

  • 60s runtime probe 的平均 FPS 是 59.999,但 minFps 出现 48.154 单帧 outlier。当前证据只说明它是单点异常,不能解释根因。M4 需要增加 percentile frame timing、GC allocation 和 spike 采样。

  • 15 个 WAV 都是 placeholder,不代表最终音频质量。

  • 暗器技能目前是白盒化命中,不是正式 projectile 物理与视觉系统。

  • 正式技能 HUD 仍未实现,O 槽只是结构预留。

  • M3 场景是测试 harness,不代表正式关卡节奏。

  • 30 分钟 1080p soak 未执行,仍然是后续 release-grade QA gate。

M4 方向

docs 仓库的 project/PROJECT_STATE.md 已把项目状态推进到 M3 完成、准备 M4。M4 不应该继续堆更多孤立战斗功能,而应该把 M3 的战斗链放进内容压力里验证。

M4 的合理方向:

  • 制作手工关卡原型,让移动、敌人和战斗不再只在白盒平台上验证。

  • 引入 Boss 和镜像 Boss,用更长的攻击节奏测试闪避、取消、技能和反馈链。

  • 为 Boss 行为准备 PlayMode / QA matrix,而不是只靠人工观察。

  • 把 M3 的 runtime probe 扩展成更细的性能采样,至少记录 percentile 和 GC spike。

  • 让技能、武器和敌人配置进入关卡语境,验证这些系统是否真的支持可玩构成。

M3 的阶段价值在这里:PROJECT-V 现在已经有一条从输入到攻击、伤害、反馈、技能、武器倍率和自动验证的完整战斗实现链。后续如果战斗不好玩,问题会更多来自调参、内容和表现,而不是“工程链路还没接起来”。