## 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_wand:remove 必须先于 add(否则重复进入会累积), # 而两者又必须都先于 equip_wand(equip_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 = 50,spark_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