feat: add simulation garden demo controls
This commit is contained in:
@@ -466,8 +466,9 @@ represent a real chosen task.
|
||||
distinct NPC colors and props, world labels identify each villager, and the
|
||||
Tab-cycled inspector shows authoritative need values, task state, destination,
|
||||
decision branch, and utility scores. The existing carried-food prop and village
|
||||
panel expose immediate consequences. A cinematic/debug toggle and repeatable
|
||||
demo reset remain Phase 6 capture tooling.
|
||||
panel expose immediate consequences. `F10` toggles the debug/cinematic
|
||||
presentation layer, while `F12` reloads the current scene as a repeatable
|
||||
simulation-garden demo reset.
|
||||
|
||||
### Exit condition
|
||||
|
||||
|
||||
@@ -652,15 +652,21 @@ Completed after the architecture gate:
|
||||
|
||||
The practical next sequence is:
|
||||
|
||||
1. Add a cinematic/debug toggle and repeatable simulation-garden demo reset.
|
||||
2. Expand resource discovery with many finite `ResourceNode` instances placed
|
||||
1. Expand resource discovery with many finite `ResourceNode` instances placed
|
||||
in meaningful foliage, animal-camp, berry, and village-stockpile contexts.
|
||||
The first distance/safety/comfort scoring pass and small authored resource
|
||||
spread exist; next, validate placement rules and grow the authored set
|
||||
carefully rather than reintroducing abstract resource zones.
|
||||
3. Expand persistence only when schedules, player state, or a real save menu
|
||||
2. Expand persistence only when schedules, player state, or a real save menu
|
||||
creates a concrete requirement.
|
||||
|
||||
Recently completed:
|
||||
|
||||
- `F10` cinematic/debug presentation toggle that hides development UI, world
|
||||
labels, and NPC name/profession labels without changing simulation state;
|
||||
- `F12` repeatable simulation-garden demo reset by reloading the current scene
|
||||
with the same authored seed and starting state.
|
||||
|
||||
This order strengthens the simulation while regularly producing visible
|
||||
progress suitable for public development updates.
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[ext_resource type="Script" path="res://simulation/persistence/SaveSlotController.gd" id="10_save"]
|
||||
[ext_resource type="PackedScene" path="res://world/jajce/JajceWorld.tscn" id="11_jajce"]
|
||||
[ext_resource type="Script" path="res://world/ui/time_dial.gd" id="12_timedial"]
|
||||
[ext_resource type="Script" path="res://world/demo/DemoController.gd" id="13_demo"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_o5qli"]
|
||||
radius = 0.4
|
||||
@@ -83,6 +84,11 @@ active_npcs_parent = NodePath("../ActiveNPCs")
|
||||
script = ExtResource("6_7mycd")
|
||||
simulation_manager = NodePath("../SimulationManager")
|
||||
|
||||
[node name="DemoController" type="Node" parent="." node_paths=PackedStringArray("ui", "active_npcs_parent")]
|
||||
script = ExtResource("13_demo")
|
||||
ui = NodePath("../UI")
|
||||
active_npcs_parent = NodePath("../ActiveNPCs")
|
||||
|
||||
[node name="VillagePanel" type="PanelContainer" parent="UI" unique_id=482126250]
|
||||
offset_left = 20.0
|
||||
offset_top = 20.0
|
||||
|
||||
@@ -32,6 +32,7 @@ var path_pending := false
|
||||
|
||||
var is_dead_visual := false
|
||||
var dead_material := StandardMaterial3D.new()
|
||||
var debug_overlay_visible := true
|
||||
|
||||
|
||||
func debug_log(message: String) -> void:
|
||||
@@ -71,6 +72,7 @@ func _apply_profession_presentation() -> void:
|
||||
profession_prop.mesh = _create_profession_prop_mesh()
|
||||
profession_prop.visible = profession_prop.mesh != null
|
||||
profession_label.text = "%s\n%s" % [npc_name, definition.display_name]
|
||||
profession_label.visible = debug_overlay_visible
|
||||
|
||||
|
||||
func _create_profession_prop_mesh() -> PrimitiveMesh:
|
||||
@@ -112,6 +114,12 @@ func set_carried_food_visible(is_visible: bool) -> void:
|
||||
carried_food_visual.visible = is_visible and not is_dead_visual
|
||||
|
||||
|
||||
func set_debug_overlay_visible(is_visible: bool) -> void:
|
||||
debug_overlay_visible = is_visible
|
||||
if profession_label != null:
|
||||
profession_label.visible = is_visible and not is_dead_visual
|
||||
|
||||
|
||||
func set_target_position(pos: Vector3) -> void:
|
||||
path_request_id += 1
|
||||
var request_id := path_request_id
|
||||
@@ -240,6 +248,7 @@ func apply_dead_visual_state() -> void:
|
||||
is_dead_visual = true
|
||||
carried_food_visual.visible = false
|
||||
profession_prop.visible = false
|
||||
profession_label.visible = false
|
||||
path_request_id += 1
|
||||
velocity = Vector3.ZERO
|
||||
current_path = PackedVector3Array()
|
||||
|
||||
@@ -65,6 +65,11 @@ func _update_presentation() -> void:
|
||||
label.text = text
|
||||
|
||||
|
||||
func set_debug_label_enabled(is_enabled: bool) -> void:
|
||||
debug_label_enabled = is_enabled
|
||||
_update_presentation()
|
||||
|
||||
|
||||
static func get_by_id(search_id: StringName):
|
||||
for node in _all:
|
||||
if node.site_id == search_id:
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
extends Node
|
||||
|
||||
@export var ui: CanvasLayer
|
||||
@export var active_npcs_parent: Node
|
||||
@export var debug_overlay_visible := true
|
||||
|
||||
var _refresh_accumulator := 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_apply_debug_overlay_visibility()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_refresh_accumulator += delta
|
||||
if _refresh_accumulator < 0.5:
|
||||
return
|
||||
_refresh_accumulator = 0.0
|
||||
_apply_debug_overlay_visibility()
|
||||
|
||||
|
||||
func _unhandled_key_input(event: InputEvent) -> void:
|
||||
if not event is InputEventKey or not event.pressed or event.echo:
|
||||
return
|
||||
if event.keycode == KEY_F10:
|
||||
toggle_debug_overlay()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.keycode == KEY_F12:
|
||||
reset_demo_scene()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func toggle_debug_overlay() -> void:
|
||||
debug_overlay_visible = not debug_overlay_visible
|
||||
_apply_debug_overlay_visibility()
|
||||
print(
|
||||
"[DemoController] %s"
|
||||
% ("Debug overlay visible" if debug_overlay_visible else "Cinematic overlay hidden")
|
||||
)
|
||||
|
||||
|
||||
func reset_demo_scene() -> void:
|
||||
print("[DemoController] Resetting simulation garden demo")
|
||||
get_tree().reload_current_scene()
|
||||
|
||||
|
||||
func _apply_debug_overlay_visibility() -> void:
|
||||
if ui != null and ui.has_method("set_debug_overlay_visible"):
|
||||
ui.set_debug_overlay_visible(debug_overlay_visible)
|
||||
|
||||
for node in ResourceNode.get_all():
|
||||
if node.has_method("set_debug_label_enabled"):
|
||||
node.set_debug_label_enabled(debug_overlay_visible)
|
||||
|
||||
for node in StorageNode.get_all():
|
||||
if node.has_method("set_debug_label_enabled"):
|
||||
node.set_debug_label_enabled(debug_overlay_visible)
|
||||
|
||||
for node in ActivitySite.get_all():
|
||||
if node.has_method("set_debug_label_enabled"):
|
||||
node.set_debug_label_enabled(debug_overlay_visible)
|
||||
|
||||
if active_npcs_parent == null:
|
||||
return
|
||||
for child in active_npcs_parent.get_children():
|
||||
if child.has_method("set_debug_overlay_visible"):
|
||||
child.set_debug_overlay_visible(debug_overlay_visible)
|
||||
@@ -19,6 +19,7 @@ static var _all: Array[ResourceNode] = []
|
||||
@export var comfort_distance := 18.0
|
||||
@export var discovery_priority := 0.0
|
||||
@export var hide_visual_when_depleted: bool = false
|
||||
@export var debug_label_enabled := true
|
||||
|
||||
@onready var interaction_point: Marker3D = $InteractionPoint
|
||||
|
||||
@@ -121,6 +122,9 @@ func _update_presentation() -> void:
|
||||
if not has_node("DebugLabel"):
|
||||
return
|
||||
var label := $DebugLabel as Label3D
|
||||
label.visible = debug_label_enabled
|
||||
if not debug_label_enabled:
|
||||
return
|
||||
var text := "%s\n%s %.1f" % [node_id, resource_id, get_amount_remaining()]
|
||||
if state != null:
|
||||
text += "\nrisk:%.2f comfort:%.0f" % [state.get_safety_risk(), state.get_comfort_distance()]
|
||||
@@ -133,6 +137,11 @@ func _update_presentation() -> void:
|
||||
label.text = text
|
||||
|
||||
|
||||
func set_debug_label_enabled(is_enabled: bool) -> void:
|
||||
debug_label_enabled = is_enabled
|
||||
_update_presentation()
|
||||
|
||||
|
||||
static func get_by_id(search_id: StringName) -> ResourceNode:
|
||||
for node in _all:
|
||||
if node.node_id == search_id:
|
||||
|
||||
@@ -91,6 +91,11 @@ func _update_presentation() -> void:
|
||||
label.text = text
|
||||
|
||||
|
||||
func set_debug_label_enabled(is_enabled: bool) -> void:
|
||||
debug_label_enabled = is_enabled
|
||||
_update_presentation()
|
||||
|
||||
|
||||
static func get_by_id(search_id: StringName):
|
||||
for node in _all:
|
||||
if node.storage_id == search_id:
|
||||
|
||||
+11
-1
@@ -9,6 +9,7 @@ const DEBUG_LOGS := false
|
||||
|
||||
var selected_npc_index := 0
|
||||
var inspector_refresh_accumulator := 0.0
|
||||
var debug_overlay_visible := true
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -88,6 +89,8 @@ func _on_state_restored() -> void:
|
||||
|
||||
|
||||
func _refresh_npc_inspector() -> void:
|
||||
if not debug_overlay_visible:
|
||||
return
|
||||
if simulation_manager == null or simulation_manager.npcs.is_empty():
|
||||
npc_inspector_label.text = "No villagers available"
|
||||
return
|
||||
@@ -122,7 +125,7 @@ func _refresh_npc_inspector() -> void:
|
||||
+ "Hunger: %.0f Energy: %.0f\n"
|
||||
+ "Carrying food: %.0f\n\n"
|
||||
+ "Why\n%s%s\n\n"
|
||||
+ "[Tab] Next villager"
|
||||
+ "[Tab] Next villager [F10] Cinematic/debug [F12] Demo reset"
|
||||
) % [
|
||||
npc.npc_name,
|
||||
profession_name,
|
||||
@@ -146,3 +149,10 @@ func _get_action_name(action_id: StringName) -> String:
|
||||
if definition != null:
|
||||
return definition.display_name
|
||||
return String(action_id).capitalize()
|
||||
|
||||
|
||||
func set_debug_overlay_visible(is_visible: bool) -> void:
|
||||
debug_overlay_visible = is_visible
|
||||
visible = is_visible
|
||||
if is_visible:
|
||||
_refresh_npc_inspector()
|
||||
|
||||
Reference in New Issue
Block a user