feat: simulation speed control with bracket keys

Press [ to slow down, ] to speed up through 6 levels: 0.25x, 0.5x, 1x, 2x, 4x, 10x. Clock delta is multiplied by the current speed, so time_of_day advances proportionally and the visual day-night cycle stays synced. Current speed shown in the village panel header. 10x makes a full day cycle watchable in ~24 seconds. Speed changes are non-destructive to simulation determinism.
This commit is contained in:
2026-07-09 00:25:57 +02:00
parent 4b5fc858f8
commit 6981c7e9bc
2 changed files with 35 additions and 2 deletions
+23 -1
View File
@@ -31,6 +31,9 @@ var latest_decisions: Dictionary = {}
var action_selector := ActionSelectionSystem.new() var action_selector := ActionSelectionSystem.new()
var action_executor := ActionExecutionSystem.new() var action_executor := ActionExecutionSystem.new()
var target_resolver := ActionTargetResolver.new() var target_resolver := ActionTargetResolver.new()
var speed_index := 2
const SPEED_LEVELS := [0.25, 0.5, 1.0, 2.0, 4.0, 10.0]
signal speed_changed(multiplier: float)
var names := ["Amina", "Tarik", "Jasmin", "Elma", "Mirza", "Lejla"] var names := ["Amina", "Tarik", "Jasmin", "Elma", "Mirza", "Lejla"]
@@ -58,11 +61,26 @@ func _ready() -> void:
func _process(delta: float) -> void: func _process(delta: float) -> void:
var ticks_due := clock.advance(delta) var ticks_due := clock.advance(delta * SPEED_LEVELS[speed_index])
for tick in ticks_due: for tick in ticks_due:
simulate_tick() simulate_tick()
func _input(event: InputEvent) -> void:
if not event is InputEventKey or not event.pressed or event.echo:
return
if event.keycode == KEY_BRACKETLEFT:
speed_index = maxi(speed_index - 1, 0)
speed_changed.emit(SPEED_LEVELS[speed_index])
if debug_logs:
print("[SimulationManager] Speed: %.2fx" % SPEED_LEVELS[speed_index])
elif event.keycode == KEY_BRACKETRIGHT:
speed_index = mini(speed_index + 1, SPEED_LEVELS.size() - 1)
speed_changed.emit(SPEED_LEVELS[speed_index])
if debug_logs:
print("[SimulationManager] Speed: %.2fx" % SPEED_LEVELS[speed_index])
func generate_npcs() -> void: func generate_npcs() -> void:
var profession_ids := SimulationDefinitions.get_profession_ids() var profession_ids := SimulationDefinitions.get_profession_ids()
for i in range(names.size()): for i in range(names.size()):
@@ -568,6 +586,10 @@ func get_recent_events(max_count: int = 5) -> Array[EconomicEventRecord]:
return results return results
func get_current_speed() -> String:
return "%.2fx" % SPEED_LEVELS[speed_index]
func _initialize_storage() -> void: func _initialize_storage() -> void:
if not storage_states.has(SimulationIds.STORAGE_VILLAGE_PANTRY): if not storage_states.has(SimulationIds.STORAGE_VILLAGE_PANTRY):
storage_states[SimulationIds.STORAGE_VILLAGE_PANTRY] = (StorageStateRecord.create( storage_states[SimulationIds.STORAGE_VILLAGE_PANTRY] = (StorageStateRecord.create(
+12 -1
View File
@@ -27,6 +27,8 @@ func _ready() -> void:
push_error("VillageUI: SimulationManager has no npc_decision_recorded signal") push_error("VillageUI: SimulationManager has no npc_decision_recorded signal")
if simulation_manager.has_signal("state_restored"): if simulation_manager.has_signal("state_restored"):
simulation_manager.state_restored.connect(_on_state_restored) simulation_manager.state_restored.connect(_on_state_restored)
if simulation_manager.has_signal("speed_changed"):
simulation_manager.speed_changed.connect(_on_speed_changed)
if "village" in simulation_manager: if "village" in simulation_manager:
_on_village_changed(simulation_manager.village) _on_village_changed(simulation_manager.village)
@@ -63,9 +65,12 @@ func _on_village_changed(village: SimVillage) -> void:
event_text = "" event_text = ""
else: else:
event_text = "\n" + event_text event_text = "\n" + event_text
var speed_text := ""
if simulation_manager.has_method("get_current_speed"):
speed_text = simulation_manager.get_current_speed()
village_stats_label.text = ( village_stats_label.text = (
""" """
Village Village [%s]
Food: %s Food: %s
Wood: %s Wood: %s
@@ -79,6 +84,7 @@ func _on_village_changed(village: SimVillage) -> void:
%s %s
""" """
% [ % [
speed_text,
round(village.food), round(village.food),
round(village.wood), round(village.wood),
round(village.safety), round(village.safety),
@@ -101,6 +107,11 @@ func _on_state_restored() -> void:
_refresh_npc_inspector() _refresh_npc_inspector()
func _on_speed_changed(_multiplier: float) -> void:
if simulation_manager != null and "village" in simulation_manager:
_on_village_changed(simulation_manager.village)
func _refresh_npc_inspector() -> void: func _refresh_npc_inspector() -> void:
if not debug_overlay_visible: if not debug_overlay_visible:
return return