PROJECT-V / GODOT

PROJECT-V Godot:普通难度平衡与代码审查

文章目录

这次 PROJECT-V 的调整围绕两个问题:玩家拿到的成长有没有真的留下来,以及一套在本机能跑的工程,能否在干净检出和导出包中重复得到相同结果。

当前主线是 Godot 4.7.2 Mono、.NET 8 与 C# 12。此前 M0–M6 文章记录 Unity 历史阶段;本篇是 Godot 主线的普通难度平衡与代码审查,不追加新的 Mn 编号。

精英压力要沿着真实刷怪链计算

只看敌人的基础血量,很难解释旧精英房为什么会突然变得难打。它同时叠加了房型、世界、个体和永久成长倍率,房间里还会初始生成三名专用精英。数量与单体强度相乘,形成了比单项配置看起来大得多的压力。

这里有一个很容易改错的地方:DifficultyScaler 的 targetEnemyCount 不是当前实际刷怪数量的来源。SpawnDirector 读取的是 roomConfig.enemySpawns。因此调整必须追到真正消费数据的位置,同时核对 spawn.count、maxAlive 和个体倍率。

本轮将初始精英数从 3 改为 1,额外生命倍率从 1.75 调至 1.15,额外伤害倍率从 1.3 调至 1.1。生化祭司仍会真实召唤最多两只寄生体,所以“一名初始精英”不等于整个房间永远只有一个敌人。

以下取自同一批 24 个固定 seed、零永久升级的参数样本;每房枚举实际名册中的可选敌种。各列是样本内的极值,不是一场战斗的完整测量,初始总 HP 也不含召唤物。

世界 精英房最大初始总 HP 精英最高单击伤害 精英最短前摇
废土 1922.5 → 355.8 46.6 → 34.7 0.485s → 0.489s
赛博 861.5 → 164.0 57.9 → 31.8 0.179s → 0.362s
生化 1289.0 → 241.3 31.8 → 24.0 0.571s → 0.576s

其中,刺客基础前摇从 0.20 秒延长至 0.40 秒,伤害从 25 调至 18;盾兵正面减伤从 70% 降到 50%。这些修改给读招和绕背留出空间。武器的基础伤害、攻速,以及主线 Boss 的基础血量和伤害没有在这轮一起重写。

关键入口,相对于 PROJECT-V 根目录:

  • godot-project/src/ProjectV.Core/Levels/DifficultyScaler.cs

  • godot-project/src/ProjectV.Core/Levels/LevelGenerator.cs

  • godot-project/src/ProjectV.Core/Data/Catalogs.cs

  • godot-project/scripts/Levels/SpawnDirector.cs

把成长反税限制在可解释的范围

如果一次升级既提高玩家数值,又把敌人同比抬高,升级的体感收益就会被吞掉。经济升级尤其不应该无故抬高即时战斗难度。

这轮的做法是把永久构筑分先截到 18,再乘 25% 进入原有关序、房序的难度基线;敌方 HP 的成长反馈系数从 0.45 降到 0.15,伤害反馈系数从 0.28 降到 0.08。留魂升级和尚未接入实际效果的协同标签不再贡献敌方压力,构筑 hash 和标签本身仍保留。

在 24-seed 门禁中,满永久成长相对于零成长的额外敌人 HP 不超过 7%,额外伤害不超过 4%。关序依旧递进,局内祝福不会再触发敌人追涨;修改前后 48 次生成记录的路线 hash 全部一致。

这让“地图有没有变化”和“数值输入有没有变化”可以分开核对。需要注意,seed 保证的是现有关卡序列;敌种与站位仍使用 Godot 全局随机,不能把相同路线 hash 理解为整场战斗完全确定。

镜像压力也改为先计算纯度的极端程度,再对称地影响生命、伤害和读招。基础生命倍率从 1.5 调到 1.2,镜像仍可拒绝。纯净和异化两端承担的是同一套极端程度规则。

强化生效,要看实际伤害和实际效用

这轮最直接的收益证据来自 COMBAT-REGRESSION:在同一个静止目标上关闭暴击,通过真实轻击接触读取目标 HP。四次配合良好的强化使长剑单次轻击由 14.4 提高到 26.784,约为 1.86 倍。

这证明了收益进入了伤害管线。它没有测量躲招、移动命中率,也没有证明真人 Boss 战一定能快 1.86 倍。

另外一组数据是理论预算。下面都是零永久升级、长剑、四次奖励,计入三连平均系数、基础暴击期望和每击 hitstop。

四次奖励样本 连续轻击理论 DPS 三个主线 Boss 的估算时间 HP / 受伤倍率
噬魂×2、气盾、疾风 32.47 46.8–58.5 秒 100 / ×1.00
内劲×2、罡气×2 60.40 25.2–31.5 秒 100 / ×1.00
内劲、剑心、狂暴×2 72.48 21.0–26.2 秒 90 / ×1.40

估算统一采用 50% 有效攻击时间;涉及毒的模型采用 80% 覆盖率。没有计入技能爆发、弱点、格挡、移动命中率和房间间隔。50% 是模型假设,不是采集到的玩家行为。低输出样本投入了防御与灵魂,它的价值也不能只用 DPS 排名。

实现上同时修复了几个“配置变化了,收益却没进来”的位置:

  • 百炼 1–5 级的毒伤分别为 3/4/5/6/7 DPS,每份淬毒另外增加 3 DPS,持续 5 秒;重复命中刷新同一个 DoT,而不是延后 tick 或制造瞬间爆发。

  • 暗器继承伤害百分比,一份平伤按整次发射的弹数分摊,避免八枚弹重复吃八次平伤。

  • 独立重击保留兵器配置的 2.5 倍;只有两次轻击后接重击,才额外获得 1.35 倍收尾加成。

  • 取得正的生命上限增量时同步回复相同 HP;重复刷新修正器不会反复回血。

这些规则分别经过配置计算、实际接触和目标 HP 的验证。只断言某个 modifier 字段增加,还不足以证明玩家真的受益。

防止持续无敌,也要清理零收益奖励

只给冷却设置下限,会留下另一个问题:满级玩家仍可能抽到一个已经无法继续缩短冷却的强化。

普通闪避现在要求冷却至少比无敌时间多 0.15 秒;技能的商店乘区和祝福乘区合并计算后,冷却不能低于原值的 40%,无敌技能还要比持续时间多至少 0.5 秒。残影伤害从每级 10 调至 4。

例如无敌已经达到 0.45 秒时,0.60 秒的普通闪避冷却便没有继续缩短的空间。奖励池和商店必须调用同一套实际冷却计算,比较变化前后的真实效果,才能过滤这时无效的“疾风”。暴击封顶和当前 U/I 技能不受益的“绵长”也按实际效用过滤。

商店对满血药和封顶疾风符拒绝购买并说明原因,F 交互跳过无效商品,避免扣魂、移除货物之后才发现没有收益。休息回复从 35% 提高到 50%,药品仍为 35%,休息和最大 HP 回复都检查了只发生一次的边界。

经济预算也要核对到账时点:在这批 72 个世界样本中,到店前最低只有 30 魂;进入 Shop 时 RoomRuntime.BeginRoom 立即清房并发放 15 魂,因此真正可购买时最低是 45 魂,才足以买 43 魂的药。把到账顺序省略,会得到相反的可购买性判断。

相关入口:godot-project/src/ProjectV.Core/Roguelite/RunBlessingPool.cs、ShopSystem.cs,以及 godot-project/scripts/Levels/InteractionService.cs。其中 ShopSystem.cs 与前者位于同一个 Roguelite 目录。

审查重点:跨流程状态不能靠画面遮罩保证

营地转场必须形成事务

原流程可能先创建正式 Run,再等待约 0.3 秒切场景。在窗口期内再次点试玩、出征或购买,就可能让场景与业务状态属于两个不同流程。

修复在 GameManager、HubController 和 SceneTransition 之间建立明确边界:营地离场后锁定状态变更回调,转场忙时拒绝新的人工导航,独立试玩进入显式的 CombatTrial 相位。试玩不触发正式局的死亡结算或存档写入。

内部死亡、结算仍可沿用转场队列。这里限制的是重复人工输入对同一事务的改写,而不是把所有转场都一概禁掉。回归覆盖了出征与试玩的双向快速点击、购买、返回,以及下一关重复导航。

未来版本存档不是损坏档

旧程序如果先按旧字段反序列化,再正常保存,可能无声抹掉新版本的合法字段;连续保存还可能把备份一并覆盖。

SaveSystem 现在先读取主档与备份的版本,拒绝未来结构,不移动或覆盖原文件。营地给出提示,禁用正式出征和永久购买,但仍允许进入独立试玩。

验证不仅检查返回值,也检查文件字节、修改时间和文件集合没有变化。SaveRecoveryTests 从 5 个实例增加到 16 个;这 11 个新增实例也是最终 Core 数量由平衡阶段的 104 增至 115 的原因。

入口为 godot-project/src/ProjectV.Core/Roguelite/SaveSystem.cs,营地与试玩边界由 godot-project/scripts/GameManager.cs 和对应场景回归共同覆盖。

瞬移与弹道,需要明确生命周期边界

连续扫掠适合处理两帧之间的真实运动,却不能直接跨过换房或坠落回入口。否则上一位置到新位置之间会形成一条并不存在的挥击或身体运动路径。

本轮在明确瞬移时结束攻击、清理缓冲和连段,取消刀光,重置攻方与受击方的运动历史;保留已有蓄力、护盾和冷却。正常走位仍使用连续扫掠,新攻击也必须继续能够命中。

挂在根节点上的玩家弹道还有自己的生命周期。清房、切世界、切试玩遭遇或冻结时,ClearOwnedBy 会先立即停用旧玩家弹;旧房间对象也先停用,再等待回收。敌弹拒绝待删除或不可处理状态,避免迟到回调继续伤害玩家。

这两个边界不能粗暴合并:致死冻结要保留真实接触姿势,下一场、重开或瞬移时才取消相应动作。运动历史的一致性断言与真实物理接触测试也分别记录,不把缓存检查写成已经执行了完整敌弹战斗。

关键文件位于 godot-project/scripts/:Player/PlayerAttack.cs、Player/PlayerProjectile.cs、Player/WeaponVisual.cs、Combat/CombatBody.cs、Enemies/Projectile.cs,以及 Levels/GameplayController.cs、Levels/CombatTrialController.cs。

一次绿灯不够,验证入口也要能失败

审查同时处理了四种交付侧的假象:

  1. 错名筛选也报绿。 run_all.ps1 和 review_1080p.ps1 先验证每个 -Only 名称及选中数量,任何错名都会直接失败,而不是漏测后输出 ALL GREEN。

  2. 只在有缓存的机器上通过。 从没有 .godot 和测试 obj 的独立发布检出开始,由脚本恢复已有依赖、编译并受控导入资源,再跑场景。这个结果证明当前机器上的干净检出可以复现,并不等于全新操作系统验收。

  3. 从新目录导出了旧工程。 export_windows.sh 根据脚本自身位置定位工程,支持 Godot 参数和输出参数;异目录启动的 fixture 检查工作目录与 --path,实际导出再单独验证。

  4. PASS 旁边还有引擎错误。 性能脚本合并检查 stdout 与 stderr 中的 ERROR / SCRIPT ERROR,结合退出码与超时判断;退出 0 且打印 PASS 也不能掩盖引擎错误。

最终证据口径如下。本文整理时复核了归档产物,没有在博客任务中重跑游戏工程。

验证层 最终结果 证据的边界
Core 115/115,通过且无跳过 配置、生成、数值、存档等逻辑,不是玩家通关率
引擎场景 19/19,另有资源导入检查通过 各用例按范围验证;部分流程用直接伤害加速,真实命中另有专项
脚本守卫 8 项通过 4 个错名筛选、3 个性能输出判定、1 个异目录导出路径
导出版检查 6 项通过 hub、attack_input、combat、progression、spawn、trial
编译 0 警告、0 错误 未来存档测试的预期保护提示不属于编译警告

导出版专项包的 ProjectV.dll 与 ProjectV.Core.dll 都与交付候选程序集核对了 SHA-256;测试临时入口之后按原字节恢复。脚本守卫中的合成错误输出只验证脚本判定能力,不代表本轮做过新的性能压测。

三世界验收画面

以下三张图来自 2026-10-26 的原生 1920×1080 验收场景,分别展示准备或出手的指定姿势。它们用于检查资源、姿势和场景表现,不是连续自然战斗录像,也不能证明本轮数值平衡的真人体验。

废土世界验收场景,主角与敌方处于指定准备姿势

废土:准备姿势,现代末世的工装、改装装备与高架环境。

赛博世界验收场景,主角与敌方处于指定出手姿势

赛博:出手姿势,义体、外骨骼与能量兵器。

生化世界验收场景,主角与敌方处于指定准备姿势

生化:准备姿势,防护服、菌根侵蚀与水墨岩彩环境。

图片来源相对 PROJECT-V 根目录:build/world_assets_2026-10-26/runtime_checks/review1080_final/gallery1080/。博客只使用这三张指定图,不同步整套工程资产或本地构建目录。

提交、证据与当前边界

截至本文发布时,审查版本已推送至私有仓库 HenRiser/project-v-game 的 codex/godot-reviewed-balance-2026-10-27 分支:

提交 说明
f9b9168ecbe2a59e587b7cea8118849ff649be8b 前一提交,纳入 Godot 主线与审查交付内容
5ae7a572f4917ae00eb4d1aef2662231b479ad3c 本文核对的最终分支 HEAD

PR #1:Godot 主线的平衡、审查修复与可复现交付 仍为 open,尚未合并;main 和 develop 的远程提交保持原值。该链接需要私有仓库访问权限。

以下证据路径均相对 PROJECT-V 根目录,指向发布检出中归档的材料:

  • reports/code_review_2026-10-27.html

  • reports/numerical_balance_2026-10-27.html

  • qa/reviews/2026-10-27/clean-regression.txt

  • qa/reviews/2026-10-27/runner-guards.json

  • qa/reviews/2026-10-27/release_verification.json

  • qa/reviews/2026-10-27/staging-audit.json

  • qa/reviews/2026-10-27/balance-before.json 与 balance-after.json

数值样本从 0x4D600006 派生 balance-0 至 balance-23,对照零/满永久成长,共 48 次生成、1126 个可选敌人参数案例和 72 个世界经济预算。它是明确范围的样本检查,不是所有 seed 的穷举。

当前仍是工程与玩法原型。按该提交的 README,中局续玩、O 技能槽、部分永久升级、分叉路线和完整镜像技能复制尚未开放。真人盲测、长期运行和跨设备表现也不在这次自动化结果里。

这一轮最重要的变化,是让压力、收益、状态边界和验证入口各自有清楚的依据。下一步应在相同武器下比较低输出、协同输出和毒构筑,采集死亡位置、Boss 入场 HP、有效攻击时间与失败原因,再修正理论模型中的假设。

原创内容采用 CC BY-NC-SA 4.0 许可;引用内容遵循原作者许可。

搜索文章