docs(roadmap): E1-② 子弹弹跳完成,勾除现状项 + 修正 Step3 为确定性速度判据

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-24 15:21:26 +08:00
co-authored by Claude Opus 4.8
parent 3eb6049b39
commit bf9bea78d8
2 changed files with 20 additions and 16 deletions
@@ -41,7 +41,7 @@ E6-a 玩家无敌帧(i-frames) ← 先行小项:Boss 弹幕公平性前置,
**现状(代码复核 2026-07-23**
- ~~元素抗性~~ ✅ **完成**2026-07-24`feat/element-resistance`):`apply_damage_from_context``ctx.damage_type``_RESIST` 表传入 `calc_damage(0, res)``enemies.json` 每型可选 `resistances{元素名:-0.9~0.9}`(支持负=弱点加伤);设计器敌人页加 6×5 抗性网格。MCP 实测:抗火0.5→半伤、弱冰-0.5→1.5×、抗性+护甲叠加45。⚠️ **已知限制**DOT 伤害(`status_manager.gd:116` 直调 `apply_damage`)暂不享元素抗性(架构上 DOT 不走 context,见 E2)。(`player_stats.gd:23 resistance` 玩家侧抗性仍占位。)
- 连锁/弹跳`bullet_manager.gd` 仅消费 `pierce_remaining`:98-101),**无** `bounce_remaining` 消费、无 `visited_targets`、无 `pow(0.9,bounce)` 衰减
- ~~连锁/弹跳~~ ✅ **完成**2026-07-24`feat/bullet-bounce`):镜像 pierce 管线——`CastStats.bounce_add``_apply_modifier` 折叠 → `_push_projectile` 写冷数据 → `_check_collision` 命中转向最近未访问敌(`_find_nearest_unvisited`)、`damage_mult×decay` 递减、`visited_targets` 防回跳、命中循环跳过已访问防密集群重复命中。bounce 优先于 pierce(耗尽后落 pierce)。`modifier_bounce` 词条上架。MCP 实测:bounce=2→3 敌 100/90/81、速度重定向证明优先级、折叠 bounce_add=2
- 归航:`bullet_manager.gd:21` 每帧建 `_enemy_pos_snapshot`(预分配满足 P6-N25)但 `_gd_integrate` 无 homing 转向计算,**快照无人消费**。
- 轨迹修正(加速/曲线):`_data +11 acceleration` 已积分,但无"转向/曲线"类修饰器写入。
@@ -51,7 +51,7 @@ E6-a 玩家无敌帧(i-frames) ← 先行小项:Boss 弹幕公平性前置,
**切分(建议 4 个子计划)**
1. ~~**元素抗性 (1-Res)**~~**完成**2026-07-24`feat/element-resistance`spec/plan `docs_dev/{specs,plans}/2026-07-24-element-resistance*`):enemies.json `resistances{元素名:-0.9~0.9}`EnemyManager `_RESIST` 查表传入 `calc_damage(0,res)`;设计器 6×5 抗性网格。
2. **连锁/弹跳 chain/bounce**:子弹冷数据 `bounce_remaining` + `visited_targets`;命中后若 bounce>0 且有未命中目标 → 重定向速度朝最近未访问敌人,衰减 `×0.9`;到 0 回收。修饰器 `modifier_bounce`。S~M
2. ~~**连锁/弹跳 chain/bounce**~~**完成**2026-07-24`feat/bullet-bounce`spec/plan `docs_dev/{specs,plans}/2026-07-24-bullet-bounce*`):冷数据 `bounce_remaining/visited_targets/decay/range`,命中转向最近未访问敌+×0.9 递减,bounce 优先于 pierce`modifier_bounce` 词条
3. **归航 homing**:子弹冷数据 `homing_strength``_gd_integrate` 消费 `_enemy_pos_snapshot` 求最近敌人,按 strength 插值转向速度向量。修饰器 `modifier_homing`。S。
4. **轨迹修正**:曲线/环绕类(angular velocity 字段)+ 对应修饰器。S(可选,最低价值,YAGNI 可延后)。
+18 -14
View File
@@ -222,25 +222,29 @@ Expected: `FAILS=0 drops=[100, 90, 81] active=0`。
- [ ] **Step 3: bounce 优先于 pierce(验收④)**
Run: godot-mcp-pro `execute_game_script`
> **确定性判据**:命中后**速度是否重定向**。bounce 会把速度转向下一目标;pierce 保持原方向。把 e2 摆在**垂直**方向即可干净区分(伤害对照会被慢速子弹在密集群内的 pierce 滞留重复命中干扰——见下注,故改测速度)。spec §2.5(b) 明确 bounce 耗尽后落到 pierce,故「bounce+pierce 子弹先弹后穿」是**符合规范**的;本步只验证「有 bounce 时该次命中走 bounce 而非 pierce」。
```gdscript
BulletManager.reset(); EnemyManager.reset(); SpatialGrid.clear()
var a = EnemyManager.spawn_enemy(Vector2(300, 0), 1000.0, 0)
var b = EnemyManager.spawn_enemy(Vector2(312, 0), 1000.0, 0)
SpatialGrid.insert(a, Vector2(300, 0))
SpatialGrid.insert(b, Vector2(312, 0))
# 同带 bounce=1 pierce=1:应弹跳(转向 b),而非穿透
var e1 = EnemyManager.spawn_enemy(Vector2(300, 0), 1000.0, 0)
var e2 = EnemyManager.spawn_enemy(Vector2(300, 100), 1000.0, 0) # 垂直方向,偏离 +x 直线路径
SpatialGrid.insert(e1, Vector2(300, 0))
SpatialGrid.insert(e2, Vector2(300, 100))
# bounce=1 + pierce=1,子弹在 e1 上沿 +x:bounce 优先 → 速度转向 e2(+y);若走 pierce → 速度保持 +x
var cold = {"bounce_remaining": 1, "visited_targets": [], "bounce_decay": 0.9, "bounce_range": 250.0, "pierce_remaining": 1}
BulletManager.spawn_bullet(Vector2(306, 0), Vector2(1, 0), 5.0, 6.0, 100.0, 1.0, 0, -1, 0, 0.0, cold)
for k in 10:
BulletManager._gd_integrate(1.0 / 60.0)
var da = 1000.0 - EnemyManager.get_hp_percent(a) * 1000.0
var db = 1000.0 - EnemyManager.get_hp_percent(b) * 1000.0
BulletManager.spawn_bullet(Vector2(300, 0), Vector2(200, 0), 5.0, 6.0, 100.0, 1.0, 0, -1, 0, 0.0, cold)
BulletManager._gd_integrate(1.0 / 60.0) # 单帧:命中 e1,bounce 应重定向朝 e2
var vx = BulletManager._data[2] # index0 vx
var vy = BulletManager._data[3] # index0 vy
var de1 = 1000.0 - EnemyManager.get_hp_percent(e1) * 1000.0
var fails := 0
if abs(da - 100.0) > 1.0: fails += 1 # a 初击满伤
if abs(db - 90.0) > 1.0: fails += 1 # b 被弹跳命中(×0.9) → 证明走了 bounce 而非 pierce(穿透会是满伤且方向不变)
_mcp_print("FAILS=%d da=%.1f db=%.1f" % [fails, da, db])
if vy < 100.0: fails += 1 # 转向 e2(+y) ≈200
if abs(vx) > 50.0: fails += 1 # +x 分量消失(pierce 会保持 ≈200)
if abs(de1 - 100.0) > 1.0: fails += 1
_mcp_print("FAILS=%d vx=%.1f vy=%.1f de1=%.1f" % [fails, vx, vy, de1])
```
Expected: `FAILS=0 da=100.0 db=90.0`(b 掉 90 证明经弹跳衰减,bounce 优先生效)。
Expected: `FAILS=0`vx≈0 / vy≈200 / de1≈100(速度转向证明 bounce 优先,pierce 会保持 +x)。
> 注(实测已确认 vx=-6.7, vy=199.9, de1=100):早前用共线慢速子弹 + 伤害对照的写法会因 pierce 耗尽后子弹滞留在 query_r 内重复命中同一敌(既有 pierce 特性,非本 feature bug),故改用垂直摆位 + 速度判据。
- [ ] **Step 4: 修饰器折叠 modifier_bounce(验收⑤)**