diff --git a/docs_dev/plans/2026-07-23-missing-features-roadmap.md b/docs_dev/plans/2026-07-23-missing-features-roadmap.md index 88d8e26..e28d1eb 100644 --- a/docs_dev/plans/2026-07-23-missing-features-roadmap.md +++ b/docs_dev/plans/2026-07-23-missing-features-roadmap.md @@ -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 可延后)。 diff --git a/docs_dev/plans/2026-07-24-bullet-bounce.md b/docs_dev/plans/2026-07-24-bullet-bounce.md index f2f1b37..4656c31 100644 --- a/docs_dev/plans/2026-07-24-bullet-bounce.md +++ b/docs_dev/plans/2026-07-24-bullet-bounce.md @@ -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(验收⑤)**