Commit Graph
69 Commits
Author SHA1 Message Date
joywayerandClaude Opus 5 cc57980e63 docs(plan): Task4 坐标实测订正——商店面板放不下,改用独立子面板
计划里 y=450 起的坐标基于「现有控件止于 y=440」的假设,实测为错:
面板覆盖 y=200–540,现有控件已排到 y≈479,_shop_warn 在 y=502,
panel 内仅余约 18px,而标题+4 行需约 161px。

改用方案 B(独立子面板,照既有 _setup_settings_ui 结构):与项目
「主面板 + 按钮开子面板」的既有模式一致,且零坐标风险。方案 A 撑高面板
后离视口底仅 28px,后续新增控件会再次撞墙。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:38:46 +08:00
joywayerandClaude Opus 5 f9486083e3 docs(plan): 订正 Task3 吞血成因——补正提交 900eaea 说明中的失实描述
900eaea 的提交信息照抄了简报里「hp_max 买到 180 后即可复现」的说法,而
Task 3 实测 + 评审独立复现证明该路径不触发:_modifiers 为空时
remove_modifiers_from 提前返回,单次合并的 add_modifier 一步算出最终值,
中间没有可观察的陈旧 hp_max。

真实风险窗口是同进程内二次 apply_run(_modifiers 已有 shop_c 加成时)。
计划里补了三行复现数据与「写回归测试必须用场景 B 前提」的告诫——
按失实说法写的断言恒绿。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:34:07 +08:00
joywayerandClaude Opus 5 68e3edbc7d docs: 订正 pct 合并公式——必须按 combine 分支,inverse 用 1−(1−step)^n
spec §2.4 与计划 Task2 写的 merged = (1+step)^n − 1 只对 hybrid 成立
(AttributeFormula 对 hybrid 用 f=1+v)。inverse 用的是 f=1−v,于是
cast_delay_mod 实际算成 f = 2−1.1^n 而非意图中的 0.9^n:
  n=2 应 0.81 实得 0.79;n=7 应 0.478 实得 0.0513
后果是该属性在第 7 次购买就撞 soft 封顶(设计意图约 22 次),
可购买次数砍到 1/3、边际收益曲线整体错误,且零诊断。

评审真机连续购买 7 次坐实。此为 spec 源头错误,非实现偏差。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 11:17:35 +08:00
joywayer 25bdc83c93 docs(plan): Task2 Step6 的 git add 补上 player_stats.gd
预检时新增的 Step 0(PlayerStats 通用访问器)改了该文件,但当时没同步更新
Step 6 的提交命令。实现者发现并正确地把它纳入提交。
2026-08-03 11:12:17 +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 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
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 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 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 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 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 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 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 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 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 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 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 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 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 3bf04c9fc0 docs(spec): R-H1 由「暂不实现」改为「已实测触发并启用」,补两种病态状态实测数据
如实记录:
- 原风险分析只预见「敌人全在射程外」,漏掉「射程内敌人全在 visited_targets 里」——
  后者经 bounce+homing 组合是该子弹的永久状态而非瞬态,且成本更高,是本次发现;
  原文把 R-H1 定性为瞬态尖峰不准确。
- 实测两种场景在 300 弹规模已达 3.14 / 4.34 ms,越过本节自定的 2.0 ms 触发线,
  故方案 3(0.2s 退避)随 Task 2 落地,摊薄约 12×。
- 残余未收敛项另立 §5.4:1500 弹摊薄后仍 3.9 / 4.5 ms,且退避会使同波齐射的
  子弹同步重试、留下 15.9 / 22.2 ms 单帧尖峰;错帧方案待决策,本次未擅自扩大范围。
§2.4 补一句指向 §5,避免「一生只查 1–2 次」与失败路径重试自相矛盾。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:04:03 +08:00
joywayerandClaude Opus 5 364ebe4c62 docs(plan): E1-③ 子弹归航逐任务实现计划(5 任务 · 含 wrapf 跨 ±π 判据与 R-H1 性能守卫)
Task0 建分支 / Task1 法术 VM 侧 / Task2 bullet_manager 转向+删死快照 /
Task3 设计器字段(含补漏的 bounce)/ Task4 MCP 运行时验收。

验收脚本全部用确定性数值断言:单帧转角上限、速率守恒、跨 ±π 的最短转向
(该摆位下有无 wrapf 会给出符号相反的结果,是有效判据)、目标失效重选、
空场直行、bounce 协同改写 homing_target_id、两层折叠 6.0。

Task4 Step7 实测 spec R-H1 病态场景(50 敌全在射程外 + 300 归航弹),
超 2ms/帧则按 spec §5 启用失败退避逃生方案。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 13:51:18 +08:00
joywayerandClaude Opus 5 049d1dda1b docs(spec): E1-③ 子弹归航设计——受限角速度中度制导 + 锁定式目标 + 删除无人消费的位置快照
手感定位为中度制导:homing_strength 即最大转向角速度(rad/s),
单层词条 3.0(350 速度下转弯半径 117px),rotated() 保持速率不变。

目标策略为发射后锁定,仅在目标死亡(get_pos_by_id 返回哨兵)或首帧时
经 _find_nearest_unvisited 重选,配 get_active_count()==0 空场守卫,
避免 query_circle(r=400, 约196格且每次新建数组)进入每帧热路径。

与 bounce 协同:bounce 命中重定向时改写 homing_target_id,
由 bounce 选目标、homing 追上去;复用 visited 过滤规避"绕已命中敌打转"死循环。

偏离路线图原文:锁定语义需 entity_id,而 _enemy_pos_snapshot 按槽位存位置
不含 id,无法支撑,故快照连同 EnemyManager.fill_pos_snapshot 一并删除
(全项目唯一调用方),净减每帧 O(敌人数) 开销。

顺带补设计器 MODIFIER schema 遗漏的 bounce 字段(现掉在 JSON 逃生舱里)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 13:36:42 +08:00
joywayerandClaude Opus 4.8 04e8cf9c09 docs(spec): 明确 bounce+pierce 组合语义——visited 持续使每敌至多命中一次(刻意,非bug)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 15:28:31 +08:00
joywayerandClaude Opus 4.8 bf9bea78d8 docs(roadmap): E1-② 子弹弹跳完成,勾除现状项 + 修正 Step3 为确定性速度判据
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 15:21:26 +08:00
joywayer e5cf6089ed docs(spec): 弹跳补充——命中循环跳过已访问敌人(防密集群重复命中) 2026-07-24 14:56:49 +08:00
joywayer 9403f80aa4 docs(plan): E1-② 子弹弹跳逐任务实现计划(3 任务·含密集群跳过已访问·SpatialGrid.insert 实测) 2026-07-24 14:56:37 +08:00
joywayerandClaude Opus 4.8 4a86ffb2c4 docs(spec): E1-② 子弹弹跳设计——镜像 pierce 管线 + 命中弹向最近未命中敌+伤害递减
缺失功能路线图 E1 子计划②。冷数据 bounce_remaining/visited_targets/decay/range;
CastStats.bounce_add + _apply_modifier 折叠 + _push_projectile 写 cold(含分支快照);
_check_collision 弹跳分支(bounce优先于pierce)+_find_nearest_unvisited;modifier_bounce 词条。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 14:44:53 +08:00
joywayerandClaude Opus 4.8 cd5f4d5892 docs(roadmap): E1-① 元素抗性完成,勾除现状项(含 DOT 抗性已知限制→E2)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 12:12:32 +08:00
joywayer abe057edf8 docs(plan): E1-① 元素抗性逐任务实现计划(3 任务 · lambda-MCP 实测) 2026-07-24 11:49:51 +08:00
joywayerandClaude Opus 4.8 e87e453abf docs(spec): E1-① 元素抗性设计——apply_damage_from_context 查表 + enemies.json resistances + 弱点(负抗)
缺失功能路线图 E1 子计划①。元素链路已通,仅补敌人抗性数据+命中查表:
enemies.json 每型可选 resistances{元素名:-0.9~0.9},EnemyManager 按 ctx.damage_type
查表传入 calc_damage(0,res);护甲不动;物理无抗性;设计器加抗性网格。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 11:45:28 +08:00
joywayerandClaude Opus 4.8 83dc1196ae docs(roadmap): E6-a 玩家无敌帧完成,勾除现状项
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 09:32:02 +08:00
joywayer c756423d57 docs(plan): E6-a 玩家无敌帧逐任务实现计划(5 任务 · TDD-MCP 实测) 2026-07-24 09:11:33 +08:00
joywayerandClaude Opus 4.8 383791db14 docs(spec): E6-a 玩家无敌帧设计——take_damage 单点门控 + 复活 hurt 反馈 + 数据驱动时长
缺失功能路线图 E6-a 先行小项。受击后 0.5s 无敌窗口(时间戳门控,
杜绝多弹同帧连扣血);顺带复活当前死代码的 PLAYER_DAMAGED emit 与
hurt 音效;spend_hp_cost 自伤不受影响;时长入 balance.json + 设计器。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 09:08:04 +08:00
joywayerandClaude Opus 4.8 1215b08e88 docs(dev): 新增原生迁移笔记——GDScript 别名陷阱 + C#/C++ 激活期接缝一致性项
沉淀两类内容并登记 docs_dev 索引:
① GDScript 陷阱:PackedArray 返回值是活引用别名(非 CoW 副本),复用成员缓冲后 return
   会被调用方遍历期间的嵌套调用就地覆写(query_circle 复用优化翻车、已回退的教训),
   附实测证据 + 通用规则(默认每次新建;省分配用 out 参数+各调用点独立缓冲)。
② C#/C++ 激活期接缝一致性项:SpatialGridCs 网格常量已对齐(已修);
   EnemyManager 原型字典 _SPEED/_ARMOR 内循环逐敌查,迁移期须在 C# 侧从 enemies.json
   自建原生数组以守 ADR-L1 铁律(a),现在不改(避免投机 churn)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 16:38:55 +08:00
joywayerandClaude Opus 4.8 09b2e1dd1d docs(roadmap): 缺失功能路线图 —— 7 史诗分组+优先级+切分+验收(战斗深度/经济/循环/Boss深化 为 P0/P1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 15:11:10 +08:00
joywayerandClaude Opus 4.8 fb90e13dd7 docs(plan): Boss 阶段+攻击模式系统实现计划(12 任务,MCP 运行时验证)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 09:39:25 +08:00
joywayerandClaude Opus 4.8 049e5930d6 docs(spec): Boss 招式增加近战 melee(原地近身范围打击)
区别于 dash 横穿冲撞,melee 为原地劈砍/砸地:前摇预警→melee_radius
内判定扣血→后摇。同步更新范围/设计器 kind 列表/验证项。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 09:29:50 +08:00
joywayerandClaude Opus 4.8 7989d8d0fd docs(spec): Boss 阶段+弹幕/位移攻击模式系统设计
阶段状态机 + 攻击模式注册表(环/扇/瞄准/旋转 + 冲刺/蓄力)+ 新建
EnemyBulletManager 敌方子弹 + 保留召唤援军 + 事件 29/30 + bosses.json
与设计器 Boss 分页。范围外:场地机制/通关演出/无敌帧/.tres。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 09:17:40 +08:00
joywayer 064b225e0b docs(designer): 修正计划 — 行编辑器成员变量不标注类型 2026-07-22 12:08:15 +08:00
joywayer 4fee708287 docs(designer): 整数元组列表编辑器实现计划 2026-07-22 12:05:56 +08:00