 joywayerandClaude Opus 5
|
622da4a18e
|
feat(shop): 货架 C 状态与购买——shop 段驱动可售集合,唯一写入点重建加成
可售集合纯数据驱动:attributes.json 的 shop 段缺失即不可售,将来解除 7 个
被阻塞属性的前置后只需加一段 JSON,零代码。
PlayerStats 新增通用生效值访问器 get_attr_value(attr_id),消除商店/UI 侧
本应出现的三处硬编码 match attr_id;_attr_effective 与裸字段在同一处
(_recompute_attrs)更新,避免两者不同步导致显示值与生效值脱节。
_attr_purchases 只存次数;每属性至多一条 _modifiers、value 为合并值
(pct 下 n 次 +step 等价于单条 (1+step)^n − 1)。这样出售退款只需次数减一后
重算,不必给 PlayerStats 新增按条撤销的 API。
所有改动次数的路径都收在 _apply_attr_purchases()——两份状态不同步会产生
「显示买了 3 次但加成只有 2 次」且无任何诊断,收敛写入点是唯一防线。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-03 11:11:08 +08:00 |
|
 joywayerandClaude Opus 5
|
6aeadb84b8
|
fix(shop): PriceFormula 大购买次数溢出静默塌陷为 1;同步计划文档残留类型名
geometric 曲线在 purchased 较大时(如 n=300,base=60 growth=1.15)raw
虽仍是合法有限 double(约 9.7e19),但已超出 int64 安全范围,roundi()
对此行为未定义/环绕,经 maxi(...,1) 静默塌陷成 1——方向与「买得越多越
贵」相反,且零诊断。仅判断 is_finite(raw) 测不出这种情况(double 本身
溢出为 INF 要到 n≈5077 才发生,晚于 int64 溢出很多),故改为
`not is_finite(raw) or raw > 9.0e15` 双重判据,触发时 push_error 并钳
到统一上限,不再依赖具体常数断言(新增用例只断言单调性与「不再塌陷回
归」)。
同时补齐 docs_dev/plans/2026-07-31-shelf-c-attribute-shop.md:64 遗漏的
`PriceFormula.Curve` → `PriceFormula.PriceCurve` 同步(enum 部分先前已
改,返回类型标注漏改),并全仓复核确认无其它残留。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-03 11:05:51 +08:00 |
|
 joywayerandClaude Opus 5
|
359da9f24f
|
docs: 订正 enum Curve → PriceCurve(与 Godot 内置 Curve 资源类冲突)
Task 1 实现时发现:enum Curve 在 4.7.1 解析期即报
"member Curve shadows a native class"——与引擎内置的 Curve 资源类同名。
实现者做了独立最小复现,确认与 class_name 无关。
spec §2.1 与计划 Task 1 的代码块都写着 enum Curve,若不订正,Task 2 的简报
会从计划里抄到错误的类型名。下游一律用 PriceFormula.PriceCurve。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-03 10:56:57 +08:00 |
|
 joywayerandClaude Opus 5
|
c6e89a0787
|
feat(shop): PriceFormula 定价模块——geometric / linear / flat 三曲线
定价集中于单一纯静态模块,无状态零依赖,故可脱离游戏进程单元断言
(与 AttributeFormula 同构)。模块不认识「属性/武器/装备」,只认识
{price_base, price_growth, curve},划分点在数据里——故货架 B 与出售退款
可直接复用,不必各写一套。
返回值下限 1:免费购买无意义,且 0 价会让「买不起」的判定失效。
偏离简报字面代码一处:枚举由 `Curve` 改名 `PriceCurve`。Godot 4.7.1
拒绝声明与引擎全局类同名的嵌套枚举("member Curve shadows a native
class",与 class_name 是否注册无关),简报/设计文档中的 `enum Curve`
在本引擎版本下无法编译,属简报代码本身的缺陷而非誊抄误差。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-03 10:55:35 +08:00 |
|
 joywayerandClaude Opus 5
|
24948c77f8
|
docs(plan): 预检订正——消除三处硬编码属性名,兑现「加属性零代码」
开工前扫描发现计划初稿违反了它自己的 Global Constraint:ShopManager
_effective_value() 与 combat_s2 的两个辅助各写了一个 match 硬编码四个属性名,
外加 4 个 ATTR_* 的 i18n 键。第 5 个属性加 shop 段后会「UI 生成了行、
但生效值读出 0 且名字是裸 id」——本特性的立身之本直接破功。
改为:PlayerStats 维护 _attr_effective 冷路径视图 + get_attr_value(id)
(热路径仍走裸字段,零开销不受影响);UI 的显示名读 attributes.json 已有的
display_name;ShopManager 暴露 get_attr_def()。三处 match 与 4 个 i18n 键全部删除。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-03 10:52:10 +08:00 |
|
joywayer
|
e41a32b751
|
chore: .gitignore 忽略 .superpowers/(子代理工作流的临时工作区)
该目录存放 SDD 流程的账本、任务简报与评审包,属过程性临时产物,
不进版本控制;否则会长期挂在 git status 里成为噪声。
|
2026-08-03 10:39:12 +08:00 |
|
 joywayerandClaude Opus 5
|
e069b76ee1
|
docs(plan): E3-② 货架 C 逐任务实现计划(7 任务 · 含回读顺序吞血风险)
Task0 建分支 / Task1 PriceFormula(TDD,含报错通道断言)/ Task2 shop 段 +
ShopManager 购买与唯一写入点 / Task3 存档 schema 2→3 / Task4 商店 UI +
4 语言 i18n / Task5 设计器 shop 段 / Task6 运行时验收 + 权威文档补录 + 回填。
Task3 写死一条顺序要求:apply_run 目前第一步就 load_save_data 设 hp,而属性
加成若在其后恢复,回读的 hp 会被尚未加成的 hp_max 钳掉——hp_max 可买到 133
之后即可复现静默吞血。Task6 Step6 专门验证该顺序。
自审订正 spec §3 影响文件表:原列 combat_manager「存档读写接入」是想当然,
profile_manager._collect_run_data 本就直接调 ShopManager.get_shop_seed(),
同样可直接调 get_attr_purchases_save(),不必绕一层。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 16:51:25 +08:00 |
|
 joywayerandClaude Opus 5
|
06d66dbd1a
|
docs(spec): E3-② 货架 C(属性购买)设计——PriceFormula 模块 + shop 段数据驱动
按用户指定的架构方向,定价由专门模块 PriceFormula 负责(与 AttributeFormula
同构:纯静态零依赖,故可脱离游戏进程单元断言)。模块不认识「属性/武器/装备」,
只认识 {price_base, price_growth, curve}——划分点在数据里,故货架 B 与出售退款
可直接复用。
可售集合纯数据驱动:attributes.json 的 shop 段缺失即不可售,自动覆盖 7 个
「已定义但被阻塞」的属性,将来解除前置只需加一段 JSON,零代码。
附完整角色属性盘点(6 类):框架内 4 个可售、权威表已定义未进框架 7 个、
PlayerStats 里权威表漏记的事实属性 2 个(mana_regen/mana_leech,权威给货架 C
举的「回蓝速度」正是前者)、资源与进度、法杖侧、全局配置。
查明 numerical_design §1.2 消耗清单缺属性购买一项,故定价属设计而非查表,
定稿后补录列为本设计的组成部分。
自审订正一处方向性错误:初稿称 cast_delay_mod 的饱和点高于 soft、需逐杖动态
判定——反了。inverse 属性数值更低=更快,三个饱和点全部低于 soft(0.1),正常
购买够不到,UI 只需 soft 一道闸。差点规定一个永远触发不了的功能。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 16:35:18 +08:00 |
|
 joywayerandClaude Opus 5
|
d7420a284f
|
docs(roadmap): 新增 E7-⑥ 计算模块化重构(用户 2026-07-31 指定的架构方向)
原则:凡涉及计算的都由专门功能模块负责,便于测试与配置。
AttributeFormula 是已验证的模板(纯静态零依赖,故不启动游戏就能单元断言)。
盘点出计算散落 8 处、仅 1 处已模块化。最严重的是伤害被劈成两半分居两个文件,
且两处都在扣护甲——目前不重复扣仅因调用点特意传 armor=0,而该约定只存在于
调用点,两个函数各自看都是完整公式。连击 +2%/层 也硬编码在管理器里。
记录立项时必须先决定的设计问题与热路径风险,避免实现期顺手定。
顺序:货架 C(含 PriceFormula)先做,本项独立立项。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 16:04:04 +08:00 |
|
 joywayerandClaude Opus 5
|
9a5f2c1271
|
chore: 补提交 addons/godot_mcp 的 35 个 .gd.uid,与全项目约定对齐
此前 godot_mcp 是全项目唯一不跟踪 .uid 的目录:
scripts/ 51 .gd / 51 .uid
addons/game_designer/ 13 .gd / 13 .uid
addons/godot_mcp/ 35 .gd / 0 .uid ← 唯一例外
且 .gitignore 无任何 .uid 规则,CLAUDE.md 亦要求新增 .gd 连同 .gd.uid 一并提交。
.uid 是稳定资源标识符,不跟踪则其它机器扫描时会重新生成不同 UID,
可能打断 uid:// 引用;Godot 官方亦建议提交。一并消除长期挂在
git status 里的 35 行噪声。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 15:00:25 +08:00 |
|
 joywayerandClaude Opus 5
|
9361bf8767
|
refactor(attr): "core" 来源提为常量;_compute_attr 补 assert;注明 execute_sub 预算独立
MOD_SOURCE_CORE 常量取代四处裸字面量(combat_manager:275,276、combat_test:20,21)。
combat_manager:273 的注释自己就警告「漏掉 remove 会累积,且 hard:50 会把它封成一个
看起来合理的数字」——而 remove 那一侧的字面量若打错一个字符,产生的正是这个零诊断
故障:旧份额撤不掉、逐次累积、被硬上限封顶成常数。常量把它变成编译期错误。
_compute_attr 缺定义时返回 0.0 是消费侧的不对称:Task 4 已硬化生产侧(attribute_tab
的 _loaded 拒绝写出零载荷),但手删 JSON 里的 cast_delay_mod 仍会让生效间隔变 0
(每物理帧施法一次)、删 move_speed 则玩家不能动。它有 push_error,但运行时 push_error
到不了任何日志通道(本期已实测),故表现为一块莫名其妙的砖。按 _recompute_attrs 空定义
分支的同款模式补 assert:release 编译掉、开发期立刻中断。
spell_evaluator:332 的新注释说「生效 cpu_limit 已含法杖份额」,读者可能推断整个 VM 都按
cpu_limit 走,但 execute_sub 的子荷载预算仍是独立的 MAX_OPS_PER_CPU * 2(=80)。补一句
注明其独立且属既有行为(改前同样脱节),不改 execute_sub 的行为。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 13:37:15 +08:00 |
|
 joywayerandClaude Opus 5
|
84c10725e2
|
docs: 订正 wand_fast 饱和点 0.05→0.0667;roadmap 关闭已决定项并澄清移速表述
【订正】wand_fast(0.25s) 的饱和点按公式 (1/60)/0.25 = 0.0667,不是 0.05。
numerical_design:21 的标注与它自己上一句的公式直接矛盾,spec/plan 另有三处同源
错误标注——均派生自一句口头转述,实测表里记的 0.0667 一直是对的。
结论也随之改对,不只是改数字:hard=0.05 使 wand_basic(饱和 0.0333) 与
circuit_fork(0.0278) 无无效区间,但 wand_fast 仍剩 [0.05, 0.0667) 这段买不到东西
(较原 hard:0.01 的 6.7 倍缩至 1.33 倍)。仍取 0.05 的理由:饱和点 = (1/60)/法杖
基准间隔,随杖而异,不存在对所有杖都最优的单一 hard——取 0.0667 让 wand_fast 干净
会使另两把杖够不到自己的饱和点,反而制造新的不可达区间。hard 数值不变。
顺带说明实测表里 wand_fast@0.0667 读到 2 帧的原因:采样点比真实边界 1/15 高 3.3e-5
(T 上高 8.3e-6 s),再叠加整帧倍数多花一帧的浮点余量效应,故实际 1 帧上界略低于
0.0667。数据没错,是标签错了。
【roadmap】E3-① 下的 cast_delay_mod 条目仍记为「待人定」并指向两个选项,而该决定
已在 ba7c885 关闭——roadmap 是查「E3 还剩什么」的索引,留着会把已关闭的决定重新打开。
改为已处理,并注明彻底消除需让 hard 逐杖化(挪进 cores.json),属独立立项。
【roadmap】「实测 200→300 px/s」读起来像发版移速由 200 改成 300,与同批改动里
numerical_design 的订正(发版是 200,300 是从未被读过的纸面值)直接冲突。改写为
「发版基准仍是 200;实测手段是临时挂 +50% 加成使生效值变 300」。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 13:36:53 +08:00 |
|
 joywayerandClaude Opus 5
|
ba7c885291
|
fix(attr): cast_delay_mod 硬上限 0.01 → 0.05,消掉两把主力杖的射速无效区间
_handle_auto_cast 用 if 而非 while,每物理帧至多施法一次,故本属性存在饱和点
= (1/60) / 法杖基准间隔:wand_basic(0.5s) ≈ 0.033、wand_fast(0.25s) ≈ 0.05。
原 hard: 0.01 在两把主力杖上都深深落在饱和区内——玩家把 cast_delay_mod 从
0.033 一路买到 0.01,射速一点没变,属"承诺了循环交付不了的东西"。
取 0.05 使 wand_fast 恰在硬上限处饱和、wand_basic 全程无无效区间。
边界实测(同一套 _physics_process 帧距扫描):wand_fast@0.05 = 1 帧/次(60/s)、
wand_basic@0.05 = 2 帧/次(30/s)、请求 0.01 被 maxf(hard,…) 钳回 0.05 后帧距不变、
soft(0.1) 对照仍 3 帧/次(20/s)、circuit_fork@0.05 = 2 帧/次。
未加任何代码钳制:下限已由 attributes.json + AttributeFormula 的 maxf(hard,…)
强制,代码里再加一个会形成重复权威,设计师调 hard 时立刻脱同步。
spec 新增 §2.2b 收录完整实测数据集(饱和点公式与三把杖的值、soft→hard 是台阶
而非曲线、周期恒为 ceil(T×60) 且整帧倍数多花一帧故实际射速恒 ≤ 名义值)——
结论易得而数据难得,故一并留档。circuit_fork 的饱和点 0.0278 标注为公式推导。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 13:18:46 +08:00 |
|
 joywayerandClaude Opus 5
|
d259205db2
|
docs(plan): 补跑守卫的另外三条进入路径,六条全部由运行时而非眼读覆盖
resume_game / _apply_padded(买卡) / apply_wand_save_data 三条原本只经静态核对,
现已在运行时跑到:均 0 条 cpu_limit=0 报错,且 deck/属性状态正确。
连同已跑的 start_game / switch_core / combat_test,六条齐全。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 13:10:24 +08:00 |
|
 joywayerandClaude Opus 5
|
f3d07c04f8
|
docs(plan): 订正 Step 7b 报错归因措辞——MCP 注入脚本的解析告警不是探针
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 13:06:49 +08:00 |
|
 joywayerandClaude Opus 5
|
04ca402f3c
|
docs(plan): 回填属性系统计划为实际执行版,勾除除合并决策外全部步骤
按 Task 5 Step 8:每个因评审而变的代码块与断言脚本都替换为真正跑通的版本,
逐处附「原写法为何不可用」——这才是回填的持久价值,否则下次复跑喂出的是
过时代码和可能已失效的断言(归航那期踩过)。
主要回填:AttributeFormula 的 pct 越界守卫与静态类型;PlayerStats 的 add_modifier
校验 / hp 钳制 / reset_for_run 清空 / 空定义分支用 assert;守卫从施法处移到 equip_wand;
cast_delay_mod 改开火时生效(原计划的装备时折叠会让局中加成到下次换杖才生效,
正好废掉货架 C);补 combat_test 注入这个原计划遗漏的消费方;属性页 SpinBox 下限、
_loaded 拒写回、autowrap、两条 push_warning。
订正计划自己的一句假话:原写「四个属性的值全部落在 0.01 格点上,故往返无量化损失」。
实测 min=-99999 时 0.1→0.100000000005821、0.01→0.00999999999476131,二者恰恰都在
0.01 格点上——成因是 Range 吸附式在 min 与 step 相差七个数量级时的抵消误差,与格点
无关;而 0.0001 容差比该漂移大七个数量级,原断言在有 bug 的版本上也是绿的。改为对
落盘文本逐字节比较。
Task 5 另记两条工具坑:运行中游戏的 push_error/push_warning 不进 MCP 的两个日志通道
(只有 print 进),故「跑一局看日志无报错」本身是空断言,必须读编辑器 Debugger 错误页
并先用故意错误做正对照;execute_game_script 不支持 await、三引号会被外层包装破坏。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 13:05:40 +08:00 |
|
 joywayerandClaude Opus 5
|
9f71108719
|
docs(attr): 守卫注释改引函数名而非会腐烂的行号;调试场景补注入顺序理由
Task 3 复审转来的两条 Minor。player_manager 守卫注释里的
「player_stats.gd:173/191」是行号引用,改动一次就失效,改为
_load_attr_definitions / add_modifier 两个函数名。
combat_test 的注入原先只有不变式没有理由,补上 remove→add→equip_wand
三者的先后依据(累积防护 + 守卫读的是注入结果)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 12:55:08 +08:00 |
|
 joywayerandClaude Opus 5
|
1aeae19187
|
docs: 订正 move_speed 300→200 与 cpu_limit「从不读」告警;路线图 E3-① 勾除并订正现状
move_speed 300 从未被任何代码读取,是纸面孤值;200 自 S0 沿用并已围绕它调校
20 波内容与 Boss 弹幕密度,以既成事实为准。cpu_limit 行的「代码硬编码 40×5、
从不读 cpu_limit」告警随本次接线失效,改记生效值构成(玩家基准 0 + 法杖 3–8)
与 hard(50) 作用于加总后的总值;基准值一并由 5 改为 0,否则重蹈 move_speed 的
「纸面值与实现长期脱节」。
路线图 E3 现状原写「player_stats.gd 有 resistance 等占位属性(4/5 stats 未接线)」
与事实不符——权威属性表是 11 个,armor/resistance 根本不在表内,是实现先于设计的
孤儿字段。E3-① 勾除并标注实际范围(只做框架 + 三条死数据),attunement_×4 /
luck / recharge_speed_mod 三项延后各附理由;顺带记 cast_delay_mod 的饱和区待人定。
E1 现状里「玩家侧抗性仍占位」一句同因失效,一并订正。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 12:54:22 +08:00 |
|
 joywayerandClaude Opus 5
|
7884e43147
|
fix(attr): 补齐属性页最后两条静默改写数据的诊断,并订正两处注释
1. 条目缺失时无任何诊断(上一轮 `and not d.is_empty()` 引入的回归)。
attributes.json 格式良好但少了 hp_max 时,_loaded 仍为 true、保存照常,
_collect 写出 {"base":0,"soft":0,"hard":0,"combine":"hybrid"}。更糟的是这个键
从此「存在」,player_stats.gd 的「缺少属性」报错也不再触发,hp_max=0 完全静默
进游戏;而 hard=0 在 hybrid 下意味着不钳制,连兜底都没有,玩家瞬死。
改为 if d.is_empty() 单独 push_warning,与 combine 那条对称。
2. min=0.0 引入的负值静默钳制同样无诊断("move_speed":{"base":-50} → 写回 0)。
运行时本就把生效值钳到 ≥0,但静默改写权威数据正是 combine 警告要防的事,
并入同一警告块保持处理对称。
3. _clean 的注释末句由描述改为禁令。原文「当前 12 个值并不依赖本函数」是事实,
但读起来像绿灯,而删掉它一直无害——直到有人放宽 min,也就是它存在的唯一场景。
4. _collect 的注释夸大了:未知键只有是对象时才存活,顶层标量键会让 _load 整体
拒绝加载。改为「保留未知属性条目」。
实测:缺 hp_max 与 base=-1234.5 两条警告均如实发出;未改动的 attributes.json
连建三次零警告零报错(误报比不报更糟,已专门验证)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 12:35:12 +08:00 |
|
 joywayerandClaude Opus 5
|
36c4f79f10
|
fix(attr): 属性页提示自动换行、加载失败拒绝写回、收紧 SpinBox 下限
三处评审必修:
1. 提示 Label 未换行,在 dock 里被裁掉。该 Label 最小宽度 786px,autowrap 为
AUTOWRAP_OFF,而 designer_panel 的 ScrollContainer 禁用横向滚动、同侪分页实际
宽度 337–887px —— 被裁的正是「inverse 的 hard 是下限」这半句,即这条提示存在的
全部理由。加 AUTOWRAP_WORD_SMART,最小宽度降到 17px,337px 下 4 行全可见。
同时补两处内容缺漏:add_int 下 hard=0 同样表示不钳制(cpu_limit 就是 add_int,
还是第一行);soft 本期无消费方,注明「留给货架 C」。
2. 加载失败后保存会写出打砖游戏的文件。_data 为空时 _collect 产出四条全 0、无
display_name 的合法 JSON,PlayerStats 照单全收 → move_speed.base=0、hp_max.base=0
直接进游戏,玩家不能移动/瞬间死亡且零诊断。加 _loaded 标志:加载失败 push_error,
_save 开头守卫拒绝写回。并按 player_stats.gd 的既有做法加逐条 is Dictionary 守卫
(畸形条目如 "hp_max": 5 原会硬崩、dock 停在半构建状态)。
3. SpinBox 下限收紧到 0.0,并订正上一版注释里的误诊。噪声不是「按 step 吸附」的
普遍现象,而是 Range 的 round((v-min)/step)*step+min 在 |min| 远大于 |v| 时的抵消
误差(min=-99999 与 step=0.01 相差七个数量级)。实测:min=-99999 且不用 _clean 时
漂移 2 处,min=0 且不用 _clean 时漂移 0 —— 收紧 min 才是真解法,_clean 并非必需。
四个属性按定义均非负,故 min=0 也更贴语义。_clean 保留作宽区间属性的廉价保险。
另:无法识别的 combine 改为 push_warning 后回落 hybrid(打字错误不该硬拒)。
按评审裁决不给 COMBINE_KEYS[selected] 加 clampi(UI.opt 已 clamp,不可达),改留注释记依赖。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 12:26:09 +08:00 |
|
 joywayerandClaude Opus 5
|
a0e205a031
|
feat(attr): 游戏设计器新增「属性」页,字段化编辑 attributes.json
按 CLAUDE.md 编辑器插件规范:控件经 designer_ui 工厂创建、标签中英双语中文在前、
combine 下拉存 key 不存显示串、_save 合并式写回防丢键、UI 在 _ready 而非 _init 构建。
另修:SpinBox 按 step 吸附会引入双精度噪声(0.01 → 0.00999999999476),
直接写回会把噪声固化进 JSON;_collect 用 snappedf(v, 1e-6) 抹平,
使「不改任何值就保存」得到逐位一致的 attributes.json。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 12:05:50 +08:00 |
|
 joywayerandClaude Opus 5
|
a6c6fdbf1e
|
docs(plan): Task5 补 Step7b——守卫零误报实测 + cast_delay_mod 饱和点上报
Task 3 复审转来两项:
① 守卫搬到 equip_wand 后需跑一局确认零误报——六条进入路径靠眼读弱于跑一局,
且误报的症状与它要报的故障一模一样,是自伤式回归。
② hard: 0.01 承诺了循环交付不了的东西:_handle_auto_cast 用 if 非 while,
每帧至多一次施法,wand_basic 在 cast_delay_mod≈0.033 即饱和,且速率按整帧
量化成 60/30/20/15 的台阶。需人定:写明饱和区,或把 hard 提到 ~0.05。
明确不在代码里加下限钳制——会与 attributes.json 形成重复权威。
另收两条 Minor:注释里会腐烂的行号引用改函数名、combat_test 注入补理由交叉引用。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:58:21 +08:00 |
|
 joywayerandClaude Opus 5
|
729c74932f
|
refactor(attr): cpu_limit 守卫移至换杖处;cast_delay_mod 改在开火时生效
守卫从 execute_compiled 搬到 equip_wand:诊断应放在能导致故障的状态转换处,
而非 2 次/秒的使用点——施法端刷屏会埋掉根因,换杖处每局只跑几次且拿得到杖名。
maxi(..., 1) 保留:错误已在换杖处大声报出,退化不再静默,而去掉它会让法术硬瘫。
订正原注释的事实错误:它声称兜住「attributes.json 缺失」与「attr_id 打错」,
但这两种 player_stats.gd:173/191 早已各自报错,守卫零覆盖。真正无人管的是
「新调用点忘了注入」(正是 combat_test 修前的样子)与「cores.json 某杖配成 0」。
cast_delay_mod 由 equip_wand 快照改为开火时相乘:_cast_timer 语义两种写法一致
(总是从上次写入值倒数),代价仅每次施法一次浮点乘法,但「下一个周期」由下次
换杖变为下次施法——玩家买急速道具期待的是后者。随之删去解释延迟生效的注释。
另在 _rebuild_wand 注入处记下 remove-before-add 为何 load-bearing:漏了会让
cpu_limit 随 install_spell 累积,而 hard: 50 会把它封成一个看起来合理的数字。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:53:16 +08:00 |
|
 joywayerandClaude Opus 5
|
6f11f4c402
|
fix(attr): 修复调试场景因 cpu_limit 基准改为 0 而退化;记录 cast_delay_mod 快照时序
combat_test 绕过 CombatManager 直接 equip_wand,拿不到 _rebuild_wand 注入的
"core" 份额,导致 cpu_limit=0 触发守卫报错、MAX_OPS 由 200 退化为 40。
镜像 _rebuild_wand 的做法在该场景自行注入(先 remove 再 add),仅修本次弄坏
的部分;该场景整体绕过 CombatManager(如从不设 mana_leech)属既有分歧,不在
本次范围内。
_cast_interval 仅在 equip_wand 时快照,install_spell 只调 _rebuild_wand 不调
equip_wand,实际再同步点是每波开战的 _transition_to_battle。行为不改,加注释
记下时序,免得后续属性商店的实现者误以为购买即时生效。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:38:08 +08:00 |
|
 joywayerandClaude Opus 5
|
a3bb778715
|
feat(attr): 接线 MAX_OPS/移速/施法间隔;法杖 cpu_limit 以加成来源接入
MAX_OPS 由硬编码 40×5 改为读生效 cpu_limit——cores.json 里逐法杖配置的
3/5/6/8 自此生效,法杖间恢复运算力区分度。玩家基准取 0,故小木法杖仍为
5 → 200 步,现有平衡零改动。
法杖份额走 add_modifier 而非调用点相加:否则 hard(50) 只钳制玩家那一份,
法杖份额加在钳制之后可使总值越界。换杖时先 remove_modifiers_from("core")
再 add,防止累积。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:35:24 +08:00 |
|
 joywayerandClaude Opus 5
|
69ddcddba6
|
docs(attr): 补记货架 C 的回读顺序陷阱;畸形条目报错说明整文件已拒绝
纯注释改动,无行为变更。
1. get_save_data 的货架 C 文档块补回读顺序:_modifiers 必须先 assign +
_recompute_attrs(),再赋 hp。反过来会让新加的 hp = minf(hp, hp_max) 拿
未加成的 hp_max 去钳,静默吞血(评审复现:回读 hp=180/100 → 换杖重算后
100/100,丢 80 HP)。今天不可达(hp_max 恒 100),但持久化 _modifiers 一
落地即活,而这个文档块正是那位实现者会读的地方。
2. 畸形条目的 push_error 补「整个文件已拒绝加载」——守卫是 return,一个坏
条目会让四个属性全部退回声明默认值,原文案读起来像只影响那一个键。
3. ATTRIBUTES_JSON 补「数据源」分区横幅,与文件自身风格一致。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:32:10 +08:00 |
|
 joywayerandClaude Opus 5
|
61445caad7
|
docs(plan): Task4 补两条约束——不做热重载 + inverse 的 hard 语义相反需在 UI 体现
remove_modifiers_from 在无命中时提前返回,不是强制重新同步原语,故热重载不能
指望它;本页与其它设计器页一致,保存后提示重启生效即可。
inverse 下 hard 是下限、0 表示钳到 0,与 hybrid/add_int 的「0 = 不钳制」相反,
设计师填 0 期待「不限制」会得到相反结果,提示文案需体现。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:32:01 +08:00 |
|
 joywayerandClaude Opus 5
|
af9c94db25
|
fix(attr): add_modifier 补校验、hp 随 hp_max 调和、reset_for_run 清加成
评审 Changes needed 的三个 Important + 五条 Minor:
1. add_modifier 补 attr_id / mode 校验。AttributeFormula 的注释明文把校验委托
给本函数("仅由 PlayerStats.add_modifier 构造…此处不做防御性校验"),而它
原先不守任何门:打错的 attr_id 会永远堆在 _modifiers 里、永不被读到、零诊断。
Task 3 的 add_modifier("cpu_limit",…) 若打成 "cpu_limits" 即 MAX_OPS=0,
所有法术静默执行零步。
2. _recompute_attrs 补 hp = minf(hp, hp_max)。hp_max 改动前事实上不可变,现在
是可动派生值而 hp 从不调和:买 +100 hp_max、血 180/200、卖掉 → 显示 180/100、
get_hp_percent 返回 1.8、heal 静默失效。
3. reset_for_run 清 _modifiers 并重算,且必须早于 hp = hp_max,否则 hp 用陈旧
的 hp_max 播种。今天 "core" 靠 _rebuild_wand 自愈,但货架 C 的购买会跨局白嫖。
Minor:_ATTR_PATH → ATTRIBUTES_JSON 并上移(_PATH 后缀在本项目专指 user:// 路径,
同类 autoload 一律 XXX_JSON);_mods_for 返回 Array[Dictionary];加载器逐条守卫
畸形值("move_speed": 200 会让 Dictionary 赋值硬崩);remove_modifiers_from 无
命中时提前返回不空发 stats_changed;货架 C 提示并入 get_save_data 并补记回读须
用 .assign()(无类型 Array 赋给 Array[Dictionary] 是运行时错误)。
_recompute_attrs 的空定义分支用 assert 而非 push_error:Task 3 接线后每次换杖/
换牌/购买都触发重算,无条件报错一局刷上百行、反而埋掉根因;assert 在 release
被编译掉且开发期首次调用即中断。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:24:30 +08:00 |
|
 joywayerandClaude Opus 5
|
8c95cdcbe3
|
docs(plan): Task3 的 MAX_OPS 接线加 cpu_limit=0 守卫
Task 2 代码质量评审建议:cpu_limit=0 的后果是所有法术静默零步,症状离根因极远。
spell_evaluator 的读取点是该故障唯一可观测处,能同时兜住 attributes.json 缺失
与 add_modifier 的 attr_id 打错两种上游失败——根因处的报错够不到这两种。
maxi(...,1) 使故障下游戏仍可玩而非完全瘫痪。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:22:23 +08:00 |
|
 joywayerandClaude Opus 5
|
a4a4f613f4
|
feat(attr): attributes.json + PlayerStats 属性框架;删孤儿字段 armor/resistance
PlayerStats 只负责加载定义、持有加成列表、把公式结果写进静态类型裸字段,
不含任何公式(公式在 AttributeFormula)。读取端零开销以满足热路径纪律
(move_speed 每物理帧被 player_manager 读)。
armor/resistance 零消费方且不在 numerical_design §1.1 权威属性表内,属实现
先于设计的残留,删除;真要做玩家侧减伤时按货架 C 属性词条立项(见 spec §2.6)。
hp_max/cpu_limit 现为派生值,从存档字段移除——回读会覆盖公式结果。
旧存档相应键忽略即可,无需提升 schema 版本(hp_max 全项目从无写入方、
cpu_limit 从未被读取)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:07:59 +08:00 |
|
 joywayerandClaude Opus 5
|
f86d6cd20e
|
docs(plan): 记录 CACHE_MODE_IGNORE 为验证 class_name 脚本的首选手段 + 加回填步骤
Task 1 实测发现:改完源码后经全局类名直调会拿到**过时结果**(返回修复前的
数值),是假通过陷阱——编辑器持有的已编译类是旧的。正确手段是
ResourceLoader.load(path, "GDScript", CACHE_MODE_IGNORE),它保留 class_name
原样且走引擎自己的编译器,故顺带证明静态类型标注真能被引擎编译。
另记 var x := <Variant 方法调用> 在 4.7.1 是无行号的编译错误而非警告。
新增 Task5 Step8:回填计划为实际执行版并勾复选框——归航那期踩过
「计划里留着过时代码和失效断言」的坑。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:04:44 +08:00 |
|
 joywayerandClaude Opus 5
|
9e3cbf8e5a
|
fix(attr): pct 越界因子变负会静默给出错数,钳到 0 并 push_error
因子 (1±v) 可为负;单条负因子被末尾 maxf(0.0,…) 掩盖,两条负因子相乘
则变回正数 —— 得到一个无报错、看起来合理、实则错误的值。实测 hybrid
base 200 两条 pct=-1.5 得 50.0(应 0.0);inverse 两条 pct=2.0 得 1.0,
延迟纹丝不动(应钳到 hard)。这条路径不需要畸形 JSON,货架 C 传个越界
value 即可触发,而本文件是所有未来平衡的必经之地。
顺带:hard 的语义因 combine 而异(inverse 是下限、0.0 不表示不钳制),
从行尾注释提升进 compute() 文档块并在 inverse 分支点明与 hybrid 相反;
补 mods 的构造契约说明;两处下界 0 加注释;ri→floored、
_COMBINE_NAMES→_COMBINE_BY_NAME;查表与循环变量补静态类型。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 11:02:44 +08:00 |
|
 joywayerandClaude Opus 5
|
cd3618c066
|
docs(plan): 补 Step3b 断言 push_error + 订正绕缓存法在类注册后失效
Task 1 评审实测发现两处计划缺陷:
① 断言 ④ 的数字部分对「add_int 拒 pct」是空的——删掉整个拒绝块 ④ 仍返回 13.0,
因为 ADD_INT 的 match 分支不读 pct_prod。拒绝行为唯一可观测证据是 push_error,
补 Step 3b 用唯一标记值 + get_editor_errors 单独断言。
② GDScript.new()+source_code+reload() 在该类被注册为全局类之后同样报
hides a global script class——Task 1 首次运行因尚未注册才侥幸通过,
后续任务照抄会失败。改为先剥离 class_name 行,或直接调已注册的全局类。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 10:53:17 +08:00 |
|
 joywayerandClaude Opus 5
|
ecf765d03e
|
feat(attr): AttributeFormula 公式模块——hybrid 连乘 / inverse 反向下限 / add_int 拒 pct
公式集中于单一纯静态模块,无状态零依赖,故可脱离游戏进程单元断言。
乘算用连乘而非线性求和:三条 +20% 得 ×1.728 而非 ×1.6,避免后期线性失控。
add_int 对离散预算拒绝 pct 并 push_error,而非静默取整掩盖配置错误。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 10:46:20 +08:00 |
|
 joywayerandClaude Opus 5
|
9bc51795c4
|
docs(plan): E3-① 玩家属性系统逐任务实现计划(6 任务 · 公式先 TDD 后接线)
Task1 AttributeFormula 纯函数(先跑断言看失败再实现)/ Task2 attributes.json +
PlayerStats 框架 + 删孤儿字段 / Task3 四处接线 / Task4 设计器属性页 /
Task5 运行时验收 + 权威文档订正。
自审修掉两处:
① Task1 的断言原用 lambda 闭包累加 fails —— GDScript 闭包对 int 按值捕获,
fails += 1 传不回外层,FAILS 会恒为 0、断言全空。改为 Array 逐条收集。
② Task4 原只写「要求」不写代码。已核对 designer_ui.gd 的真实签名
(spin/opt/load_json/save_json 等)并写出完整可抄的实现,避免实现者照
猜测签名写。
另补:hp_max/cpu_limit 转为派生值后必须从存档字段移除,否则回读覆盖公式结果;
并在代码注释里留下货架 C 需持久化 _modifiers 而非派生值的提示。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 10:42:18 +08:00 |
|
 joywayerandClaude Opus 5
|
d3c5edb1cb
|
docs(spec): E3-① 玩家属性系统设计——公式模块 + 修三条死数据 + 范围裁剪
范围按权威文档裁剪:路线图原写的属性名(暴击/急速/范围/吸血/减伤)是拟稿推测,
不存在于任何权威文档;numerical_design §1.1 定义的 11 个属性才是权威。
本期只做「框架 + 修既有死线」,排除 attunement×4(新玩法维度)、luck(暴击链是死的)、
recharge_speed_mod(充能系统压根不存在)。
加成不做简单叠加:每属性在 JSON 声明 combine 公式——hybrid 连乘、
inverse 反向且下限钳制、add_int 拒绝 pct。公式集中在独立的 AttributeFormula
纯静态模块,无状态零依赖,故公式正确性可脱离游戏进程单元断言。
自审修正:法杖 cpu_limit 改为以加成来源接入而非调用点相加——否则 hard 上限
只钳制玩家那一份,法杖份额加在钳制之后可使总值越界;顺带使加成层从第一天
就有真实消费者。
move_speed 取既成事实 200 并订正权威表的 300:该值从未被任何代码读取过,
而 200 自 S0 沿用并已围绕它调校 20 波内容——与归航定价那次相反,
「以权威为准」要看那条权威有没有被实践检验过。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-31 10:32:41 +08:00 |
|
 joywayerandClaude Opus 5
|
e651072b9b
|
docs: 订正归航手感论证的运动学错误 + 记录定价越权与用户决策
【spec §2.0】原论证只算转弯半径就断言「急转的敌人能甩掉」,从未拿它对照敌人
实际速度 —— 明写此错,并补上缺的那一步运动学核算:跟踪横向速度 v、距离 d 的
目标所需角速度 ω≈v/d,故跟丢条件是 d < v/ω_max(近距离判据)。代入实际数值
(敌 45~140 px/s、弹 ~350 px/s) 重列强度表,标出发版值 1.5、给出各档对最快敌人
的跟丢距离。说明中远距离不是区分点(1.5 与 3.0 余量分别近 5 倍/10 倍,都能可靠
命中),真实失手方式是【近距离过冲】——目标坐进转弯圈内、几何上无法收敛,
而这正是 1.5 想要的手感。叠加表按 1.5 递增重列,堆到必中仍是合法 build 收益。
【spec §2.8】承认原「与 pierce/bounce 对齐」的论证绕过了权威:那两个词条本身
就不在定价表里,拿两个未定价条目互相对齐等于自建平行标准。而
numerical_design.md 确实给 homing 定过价(Tier 3 / Mana 40),且该表是活的权威——
其 Mana 列与 spells.json 每个已实现条目精确吻合,仅 homing 一行偏离。记录用户
决策及其取舍:这个词条能卖同族价,是因为它被调到了同族强度。
【numerical_design.md】homing 行按 P6-N2/N25 同样风格标注:原行删除线保留可
追溯(不抹掉「曾判定为 Tier 3」这个记录),表下补注说明 Homing Force 语义已废
(实现为最大转向角速度 rad/s,与 5.0 不同量纲不可比)、Mana 40 被同族标准取代、
实际发版 homing 1.5 / Mana 8 / 商店 18,并链接 spec。
【architecture_design.md】§4.2 冷数据注释的示例值 3.0 → 1.5(含转弯半径 233px)。
【plan】Task 1 Step 5/6 的 JSON 与断言期望值同步为 1.5;验收⑧(Step 6/6b)重跑
并更新为 folded=3.00 / e2e_2stack=3.000 / e2e_1stack=1.500;Step 8b 补设计器
往返与 SpinBox 格点确认输出。新增顶部醒目段落说明【机制测试①②③④⑦里的 3.0
是测试局部值、与发版值刻意解耦】——平衡调整不应导致机制测试失败,不要为了
数字一致去改它们;唯一应随发版值走的是⑧。Step 7 注明平衡调整不影响性能守卫
(强度只进转向数学,不参与决定 query_circle 频率的任何分支),未重跑。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 18:13:58 +08:00 |
|
 joywayerandClaude Opus 5
|
4b12ffbfb1
|
fix(homing): modifier_homing 强度 3.0 → 1.5 rad/s,使 8 蓝同族定价名副其实
发版前平衡复核发现 3.0 rad/s 名不副实:spec §2.0 声称「急转的敌人能甩掉」,
但只算了转弯半径、从未对照敌人实际速度。敌人 45~140 px/s vs 子弹 350 px/s,
400px 接近过程(~1.14s)里最快敌人只需约 0.38 rad 航向修正,而 3.0 rad/s 可转
3.4 rad —— 余量近 10 倍,实际是「稳定命中」而非「中度制导」。
1.5 rad/s → 转弯半径 233px,对最快敌人(140px/s)在 93px 内跟丢(d < v/ω),
贴脸急转真能甩掉,兑现原批准的设计意图。
mana_cost / shop_cost 不动(8 / 18,与 pierce/bounce 同族)。选「降强度」而非
「抬价到 numerical_design.md 原定的 Tier 3 / Mana 40」,因后者会牵动整条 Tier 3
定价与玩家蓝池预算,属另一次立项。
实测:单层 e2e=1.500、两层折叠 e2e=3.000、设计器往返无损(1.5 正落在
SpinBox step=0.05 格点)、商店池仍可抽。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 18:13:26 +08:00 |
|
 joywayerandClaude Opus 5
|
a119ec9ab1
|
docs(arch): 补删 ProjectileDef.reset() 里遗留的 homing_force 赋值
上一提交删了声明与注释、漏了 31 行后 reset() 内的赋值,
导致同一代码块自相矛盾(注释声明该字段不存在,正文仍在赋值)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 17:47:56 +08:00 |
|
 joywayerandClaude Opus 5
|
3e45ef0059
|
docs: 计划回填实际执行的验收脚本 + 订正权威文档自相矛盾处 + 性能数字改区间
【计划 Task 4】原稿四个脚本有缺陷,照它复跑会得到假失败与空通过,现已替换为
实际执行并通过的版本,每处旁注「原脚本为何有缺陷」,并勾上完成的复选框:
- Step 2 敌人摆位 (400,200) 距原点 447px 已出 homing_range=400,实测 FAILS=1;
这是测试摆位错误而非实现缺陷(精确距离过滤行为正确)。改到 (300,150)。
- Step 6 内联复刻了折叠逻辑与商店谓词——在测自己;改调真实 _apply_modifier
与 ShopManager._available_pool(),另补 compile_wand→execute_compiled 端到端。
- Step 7 无墙钟起搏,40 帧全停在退避窗内、守卫沦为空断言;且几何让子弹直穿
敌人簇,多计约 1.5ms 碰撞开销。改为 60fps 起搏 + spec §5.2 环形摆位,
frame1 与稳态峰值分开报。
- Step 8 只对源码 grep 字符串,不是往返;改为真实实例化 spell_tab 对真实
spells.json 做 8 条 type-1 的回读→写回比对。
回溯表补「观测方式」列,标出⑥是唯一一条状态推断而非直接观测。
【architecture_design.md】同一文档内自相矛盾:
- CastStats 块 homing_force(「归航强度,向最近敌人偏转」)与 §4.2 新写的
「最大转向角速度 + 锁定式目标」冲突 → 订正为 homing_add(弧度/秒);
顺带订正确证过的 pierce_add / bounce_add(原写 *_count)。该块其余字段
仍有既有漂移,加 ⚠️ 注明未核对、以 cast_stats.gd 为准,不扩大改动范围。
- ProjectileDef 的 homing_force 删除——projectile_def.gd 无任何 homing 字段,
归航冷数据由 _push_projectile 直接写入 BulletManager。
- §4.2 bounce 协同散文补上实际存在的 if cold.has("homing_strength") 前置守卫。
- get_nearest_pos 代码片段:_enemy_count → _active_count(前者不存在)、
未命中返回值 Vector2.ZERO → origin、删除不存在的 _visible_flags 过滤。
【spec】
- §4 第⑥条措辞「不触发 query_circle」字面为假(_check_collision 每帧无条件
发一次),改为「不因归航触发」,并写明这是唯一一条间接验证及其封闭性论证。
- §5.5 峰值改为区间表述(① 4~5ms / ② 5~7ms @1500),注明编辑器/调试构建、
运行间离散(同场景三次得 5.61/5.09/7.29ms),判定回归看是否出现周期性复发
尖峰与是否越过 16.67ms,勿拿单值比对;并记录几何对测量的影响。
- §5.4 勘误:「1493 个互异到期值」不可能成立(jitter 只能产出约 200 个整数值,
同帧失败又共用同一 now),复测为跨度 223ms / 222 个互异值,结论不变。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 17:33:16 +08:00 |
|
 joywayerandClaude Opus 5
|
4b09cd1064
|
fix(homing): 抖动公式的整数除法加 @warning_ignore,消掉 INTEGER_DIVISION 告警
(bullet_idx * HOMING_RETRY_MS) / maxi(1, _active_count) 的截断是有意的 ——
抖动只需毫秒粒度的偏移,小数部分丢弃即所需语义。加注解让编辑器面板对
项目文件保持零告警,使验收标准⑩「无告警」真正成立。
行为不变(注解为编译期),复测:①②③ FAILS=0 / ah=0.25000 / max_step=0.050000
/ 速率 350.0000;1500 弹同帧集体失败的到期时刻跨度 223ms、222 个互异值,抖动照常生效。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 17:32:43 +08:00 |
|
 joywayerandClaude Opus 5
|
14136b1223
|
docs: 退役 P6-N2/P6-N25 并订正 §4.2 归航设计——删除快照的连带订正
E1-③ 归航实现删除了 _enemy_pos_snapshot 与 EnemyManager.fill_pos_snapshot
(锁定式目标需 entity_id,快照按槽位存位置不含 id),权威文档随之失准,一并订正:
- docs/README.md:P6-N25(快照须为类成员)与 P6-N2(Homing 弹共用快照)双双失去
约束对象,改为删除线 + ⚠️ 已退役(2026-07-30) 并指向 spec §2.4/§2.7。不删条目,
避免编号规范留下悬空引用。
- architecture_design.md §4.2:homing 伪代码整段改写为实际算法——冷数据
homing_strength(弧度/秒)/homing_range/homing_target_id、发射不解析目标首帧惰性
锁定、仅目标失效时经 _find_nearest_unvisited 重选、wrapf 最短转向 + clampf 限
角速度 + rotated() 保速率、空场守卫、失败退避+抖动、bounce 协同改写目标并撤销
退避键。性能数字一律指向 spec §5,不另起一套。
- 冷数据字段表 homing_force → homing_strength/homing_range/homing_target_id。
- EnemyManager API:fill_pos_snapshot 换成实际存在的 get_pos_by_id(含哨兵约定);
get_nearest_pos 与自动瞄准改为「直接扫描 SoA」,原文称与 homing 快照共用属误述。
- S0 性能表 EnemyManagerCs 行标注该实测含已删除的 fill_pos_snapshot(保留历史数字)。
- MinionManager.fill_pos_snapshot 标注为未实现提案,并纠正其「供 homing 用」的注释。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 17:01:56 +08:00 |
|
 joywayerandClaude Opus 5
|
d498097005
|
docs(roadmap): E1-③ 子弹归航完成,勾除现状项 + 记录快照删除这一有意偏离
「现状」归航行与切分列表第 3 项改为完成态,格式对齐已完成的 ①②。
显式记录与本文档原方案的偏离:未消费 _enemy_pos_snapshot 而是删除之 ——
锁定式目标需 entity_id,而快照按槽位存位置、不含 id,结构上支撑不了该语义。
另记退避 + 抖动这一同期落地的性能措施(详见 spec §5)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:54:13 +08:00 |
|
 joywayerandClaude Opus 5
|
df81e9eafa
|
style(homing): 设计器 homing 标签补单位提示「弧度/秒」
3.0 这个值形似 0~1 的强度系数,不标单位易被误读为「归航强度」而调错量级。
文件内已有括号提示先例(如「n(每 n 次)」)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:40:11 +08:00 |
|
 joywayerandClaude Opus 5
|
55f96e1a1c
|
feat(homing): 设计器 MODIFIER 表单加 homing 字段,并补上期遗漏的 bounce 字段
bounce 自上期起一直掉在「其它(JSON)」逃生舱,违反 CLAUDE.md 字段化规范,
与 homing 同处 schema,一并补上。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:30:10 +08:00 |
|
 joywayerandClaude Opus 5
|
ffc75acead
|
docs(spec): §5.6 触发条件改为弹数阈值 + 新增 §5.7 退避墙钟不免疫时间缩放
§5.6:把重新立项的触发条件从场景描述改为可直接计算的弹数阈值 —— 成本严格线性于
「同帧创建且首次选目标全部失败的归航弹数」约 9.5µs/颗,附 200/500/1000/1750 颗的
对照表,约 1750 颗为理论击穿点(MAX_BULLETS=2048 故容量内可达)。并注明 visited
类场景因 visited_targets 线性扫描,实测高于线性外推,实际击穿点更低。
§5.7 新增潜在项(休眠,不修):退避基于 Time.get_ticks_msec() 是墙钟,不受
Engine.time_scale 影响,而 TimeManager 正是为慢动作/冻结时间 Core 驱动 time_scale 的。
grep 确认 set_time_scale 当前零调用方,故今日无害;若落地 0.2× 慢动作,200ms 只跨
约 2.4 个物理帧而非 12,抖动摊薄失效,且表现为慢动作期间掉帧。
记录替代方案(触发时再实施):改用物理帧计数 HOMING_RETRY_FRAMES=12,免疫时间缩放、
略便宜、消除 ms↔帧量纲错配;项目已有现成的 TimeManager.game_tick 且注释明写不受
time_scale 影响,正合用。触发条件为 set_time_scale 出现第一个调用方。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:26:36 +08:00 |
|
 joywayerandClaude Opus 5
|
28f4047096
|
fix(homing): bounce 协同路径遗留过期退避键,使子弹对着尸体转向且拒绝重新锁定
homing_target_id 有两个写入方,不变式「homing_retry_at 只在目标无效时才有意义」
只在其中一方成立:_apply_homing 重选成功时会 erase 该键,bounce 那行不会。
后果是一颗 bounce+homing 子弹若先经历过一次重选失败、再弹跳到 next_id、而 next_id
随即死亡(弹跳目标是刚打过的敌人,随即死亡是常态),它会对着尸体继续转向,并在
残留退避窗口内(最多 400ms ≈ 24 帧)拒绝重新锁定,哪怕 50px 外就有活敌人。
这恰好废掉了那行 bounce 协同代码存在的意义。
修法与重选成功路径对称,补一行 cold.erase("homing_retry_at")。运行时复现确认:
阶段1 重选失败 -> retry_at 存在=true, tgt=-1
F bounce 后: tgt=3 (expect 3) retry_key_still_present=false (修前 true)
F 目标死亡后能否立刻重选: tgt=4 重选成功=true (修前被残留退避压住停在 3)
另两处:
- 调用方守卫注释的「省约 87%」改为 64% —— 87% 出自代理微基准推算,已被真实
端到端实测(2.107→1.812ms)推翻,热路径里挂陈旧乐观数字会误导后来人判断该守卫去留。
- jitter 取模的 6 行不可达性论证压缩为一行(运算保留作索引越界兜底,成本为零)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:26:17 +08:00 |
|
 joywayerandClaude Opus 5
|
4ef8012b6e
|
docs: 首帧锁定尖峰决策为「接受」+ Task4 Step7 改为两场景单帧峰值回归守卫
spec §5.6:残余的首帧尖峰(1500 弹同帧创建且首次选目标全失败时 16~22ms)
决策接受不处理——触发条件是三个苛刻条件的合取属合成最坏情况、一次性不复发、
压下它需牺牲「首次锁定即时」的手感或改变归航/bounce 语义。附重新立项触发条件。
plan Task4 Step7:原只测「敌人全在射程外」,补上评审发现的更严重场景
「射程内全在 visited」(visited 只增不减故为永久状态);指标由 60 帧均值
改为单帧峰值——退避把成本摊成 1 重选帧 + 11 退避帧,均值会掩盖尖峰,
而帧预算 16.67ms 下尖峰才是玩家可见的。性质由决策关卡降级为回归守卫。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:15:01 +08:00 |
|
 joywayerandClaude Opus 5
|
5cc40e72e8
|
docs(spec): §5 补「朴素退避会同步而非打散」二次发现 + 抖动方案 + 单帧峰值对比
新增 §5.4「二次发现」:固定退避下尖峰每 12 帧复发(附逐帧耗时序列证据),
根因是同帧失败的子弹到期时刻相同、被退避锁进同相;这与「退避能摊薄尖峰」的
直觉相反,且摊薄均值会掩盖它 —— 后来人写类似退避/重试逻辑会踩同一个坑,故写清。
含抖动实现、为何用占比式而非 bullet_idx % 窗口宽度、HOMING_RETRY_MS 一值两用的理由。
§5.5 抖动前后单帧峰值对比表(稳态峰值全部回到帧预算内,超预算帧数 0/39)。
§5.6 记录残余:初次锁定帧(1500 弹 16.2/22.0ms)非退避问题,而是「首次锁定即时」
手感属性的直接结果,压下它需牺牲手感,属设计决策,未擅自处理。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:13:00 +08:00 |
|
 joywayerandClaude Opus 5
|
71240931af
|
perf(homing): 退避到期时刻加抖动,消除每 12 帧复发的集体重试尖峰
二次发现:固定 200ms 退避并没有消除尖峰,只是让它变成周期性复发。按真实 60fps
起搏复测,1500 弹 visited 场景逐帧耗时在第 1/13/25/37 帧稳定出现 ~21ms,永不衰减:
21.9 2.8 2.9 ... 3.1 | 21.8 2.8 ... | 21.0 2.9 ... | 20.9 3.7 3.9 3.8
根因是朴素退避会把子弹锁进同相而非打散 —— 同帧失败的子弹拿到同一个 now,到期时刻
完全相同,一个退避周期后又整齐地一起重试;同波齐射本就天然同相,此后再无机会错开。
摊薄后的均值数字恰恰掩盖了这一点。
修法是抖动到期时刻,铺满 [200,400) ms ≈ 恰好一个退避周期 ≈ 12 帧。
用「bullet_idx 在活跃弹数中的占比」而非 bullet_idx % HOMING_RETRY_MS:后者在弹数少于
窗口宽度时只铺开 _active_count 毫秒(20 颗弹 → 20ms ≈ 1.2 帧,等于没打散)。
实测打散质量:1500 颗同帧集体失败 → 互异到期值 1493 个、覆盖 14 帧、单帧最多 120 颗
(理想 125)。
单帧峰值(60fps 起搏 40 帧,稳态即排除初次锁定帧):
① 全射程外 1500 13.6~15.7ms 复发 → 4.40ms 300 3.2ms → 0.92ms
② 全 visited 1500 20.9~21.9ms 复发 → 5.61ms 300 4.6ms → 1.15ms
稳态超 16.67ms 的帧数均为 0/39。
首次锁定即时的行为未受影响(抖动只作用于失败后的重试),速率守恒、单帧转角上限、
退避窗口内零查询、到期后重试成功并 erase 键,断言全绿。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-07-30 16:12:40 +08:00 |
|