feat: Implement Live Director System for interactive simulation control
- Added waypoint context updates to handle action queue statuses in `waypoint_context.gd`. - Introduced new scene file `manwalk.scene` with terrain and stickman setup. - Created architecture summary for the Live Director System detailing core state transitions, physics mechanics, UI elements, and action execution. - Specified class contracts and interfaces for the Live Director implementation in `phase_12_live_director.md`. - Defined state transitions, input handling, and queue editing mechanics for the Live Director feature.
This commit is contained in:
+29
-12
@@ -10,6 +10,7 @@ extends PopupPanel
|
||||
|
||||
const ACTION_REGISTRY := preload("res://scripts/action_registry.gd")
|
||||
const STICKMAN_RIG := preload("res://scripts/stickman_rig.gd")
|
||||
const ACTION_RUNNER := preload("res://scripts/stickman_action_runner.gd")
|
||||
|
||||
signal edit_requested(index: int)
|
||||
signal delete_requested(index: int)
|
||||
@@ -65,14 +66,15 @@ func refresh() -> void:
|
||||
_drag_index = -1
|
||||
_drag_target = -1
|
||||
|
||||
var queue: Array[Dictionary] = []
|
||||
var queue_view: Array[Dictionary] = []
|
||||
if rig != null and is_instance_valid(rig):
|
||||
queue = rig.get_queue()
|
||||
queue_view = rig.get_queue_view()
|
||||
_title_label.text = "Stickman: %s" % (String(rig.name) if rig != null and is_instance_valid(rig) else "?")
|
||||
_empty_label.visible = queue.is_empty()
|
||||
_empty_label.visible = queue_view.is_empty()
|
||||
|
||||
for i: int in queue.size():
|
||||
_rows.append(_make_row(i, queue[i]))
|
||||
for i: int in queue_view.size():
|
||||
var entry: Dictionary = queue_view[i]
|
||||
_rows.append(_make_row(i, entry.get("action", {}), int(entry.get("status", ACTION_RUNNER.QueueStatus.NOT_STARTED))))
|
||||
|
||||
|
||||
func _build_ui() -> void:
|
||||
@@ -129,7 +131,7 @@ func _build_ui() -> void:
|
||||
min_size = Vector2i(460, 360)
|
||||
|
||||
|
||||
func _make_row(index: int, action: Dictionary) -> PanelContainer:
|
||||
func _make_row(index: int, action: Dictionary, status: int) -> PanelContainer:
|
||||
var panel := PanelContainer.new()
|
||||
panel.add_theme_stylebox_override("panel", _row_style(Color(0.0, 0.0, 0.0, 0.0)))
|
||||
|
||||
@@ -145,10 +147,15 @@ func _make_row(index: int, action: Dictionary) -> PanelContainer:
|
||||
summary.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
summary.text = "%s %s" % [ACTION_REGISTRY.icon(String(action.get("type", ""))), ACTION_REGISTRY.summarize(action)]
|
||||
row.add_child(summary)
|
||||
var status_label := Label.new()
|
||||
status_label.text = _status_label(status)
|
||||
status_label.modulate = Color(1.0, 1.0, 1.0, 0.65) if status == ACTION_RUNNER.QueueStatus.COMPLETED or status == ACTION_RUNNER.QueueStatus.INTERRUPTED else Color.WHITE
|
||||
row.add_child(status_label)
|
||||
|
||||
var edit := Button.new()
|
||||
edit.text = "✎"
|
||||
edit.tooltip_text = "Edit"
|
||||
edit.disabled = status == ACTION_RUNNER.QueueStatus.COMPLETED or status == ACTION_RUNNER.QueueStatus.INTERRUPTED
|
||||
edit.pressed.connect(func() -> void: edit_requested.emit(index))
|
||||
row.add_child(edit)
|
||||
|
||||
@@ -161,6 +168,7 @@ func _make_row(index: int, action: Dictionary) -> PanelContainer:
|
||||
var drag := Button.new()
|
||||
drag.text = "≡"
|
||||
drag.tooltip_text = "Drag to reorder"
|
||||
drag.disabled = status == ACTION_RUNNER.QueueStatus.ACTIVE or status == ACTION_RUNNER.QueueStatus.COMPLETED or status == ACTION_RUNNER.QueueStatus.INTERRUPTED
|
||||
drag.mouse_default_cursor_shape = Control.CURSOR_MOVE
|
||||
drag.gui_input.connect(_on_drag_handle_gui_input.bind(index))
|
||||
row.add_child(drag)
|
||||
@@ -226,6 +234,20 @@ func _row_style(bg: Color) -> StyleBoxFlat:
|
||||
return sb
|
||||
|
||||
|
||||
func _status_label(status: int) -> String:
|
||||
match status:
|
||||
ACTION_RUNNER.QueueStatus.COMPLETED:
|
||||
return "✓ Done"
|
||||
ACTION_RUNNER.QueueStatus.INTERRUPTED:
|
||||
return "↯ Interrupted"
|
||||
ACTION_RUNNER.QueueStatus.ACTIVE:
|
||||
return "▶ Active"
|
||||
ACTION_RUNNER.QueueStatus.PENDING:
|
||||
return "• Pending"
|
||||
_:
|
||||
return ""
|
||||
|
||||
|
||||
func _on_drag_handle_gui_input(event: InputEvent, index: int) -> void:
|
||||
if event is InputEventMouseButton and (event as InputEventMouseButton).button_index == MOUSE_BUTTON_LEFT:
|
||||
if (event as InputEventMouseButton).pressed:
|
||||
@@ -281,9 +303,4 @@ func _move_action(from: int, to: int) -> void:
|
||||
var queue := rig.get_queue()
|
||||
if from < 0 or from >= queue.size() or to < 0 or to >= queue.size():
|
||||
return
|
||||
var action: Dictionary = queue[from]
|
||||
rig.remove_action(from)
|
||||
var target := to
|
||||
if to > from:
|
||||
target -= 1
|
||||
rig.insert_action(target, action)
|
||||
rig.move_action(from, to)
|
||||
|
||||
Reference in New Issue
Block a user