Files
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

68 lines
2.3 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## CombatTest — S1 最小战斗调试场景
## 目标:玩家自动发射 spark_bolt,子弹命中敌人,敌人死亡,屏幕显示击杀数
## 验收:P-S1-01 ~ P-S1-05
extends Node2D
const SPAWN_ENEMIES: int = 50 # S1 验收:50 只散兵(充分验证伤害)
var _player_node: Node2D = null
var _perf_label: Label = null
var _spawned: bool = false
func _ready() -> void:
_setup_debug_ui()
PlayerManager.set_player_node(_player_node)
# 装备法杯:wand_basic + spark_bolt
var loadout: Dictionary = WandPreset.make_default_loadout()
# 本场景绕过 CombatManager,故须自行注入法杖运算力份额(否则 cpu_limit=0 → MAX_OPS 退化)
# 顺序理由见 combat_manager._rebuild_wandremove 必须先于 add(否则重复进入会累积),
# 而两者又必须都先于 equip_wandequip_wand 里的 cpu_limit<=0 守卫读的就是注入结果)
PlayerStats.remove_modifiers_from(PlayerStats.MOD_SOURCE_CORE)
PlayerStats.add_modifier("cpu_limit", "flat", float(loadout["core"].cpu_limit), PlayerStats.MOD_SOURCE_CORE)
PlayerManager.equip_wand(loadout["core"], loadout["compiled"])
_run_spawn()
func _process(_delta: float) -> void:
_update_perf_ui()
func _run_spawn() -> void:
var arena: float = 600.0
for _i in SPAWN_ENEMIES:
EnemyManager.spawn_enemy(
Vector2(randf_range(-arena, arena), randf_range(-arena, arena)),
50.0 # P-S1-01: HP = 50spark_bolt 卷 3 伤
)
_spawned = true
print("[CombatTest S1] 生成完成: %d 敌人, wand_basic+spark_bolt 装备" % SPAWN_ENEMIES)
func _update_perf_ui() -> void:
if not _spawned or not _perf_label:
return
_perf_label.text = (
"FPS: %.1f\n敌人: %d\n击杀: %d\n子弹: %d\nTick: %d\n池: %s" % [
Engine.get_frames_per_second(),
EnemyManager.get_active_count(),
PlayerManager.kill_count,
BulletManager.get_active_count(),
TimeManager.game_tick,
DamageContextPool.get_pool_usage()
]
)
func _setup_debug_ui() -> void:
var canvas := CanvasLayer.new()
canvas.name = "DebugUI"
add_child(canvas)
var perf := Label.new()
perf.name = "PerfLabel"
perf.position = Vector2(16, 16)
perf.add_theme_font_size_override("font_size", 18)
canvas.add_child(perf)
_perf_label = perf
var p := Node2D.new()
p.name = "Player"
add_child(p)
_player_node = p