This commit is contained in:
Bryce
2025-08-01 08:34:51 -07:00
parent 15f11fc0f3
commit 44d3f10875
77 changed files with 605 additions and 713 deletions

0
.gitattributes vendored Normal file → Executable file
View File

0
.gitignore vendored Normal file → Executable file
View File

0
addons/cutscene_editor/CHANGES.md Normal file → Executable file
View File

17
addons/cutscene_editor/CutsceneEditorPlugin.gd Normal file → Executable file
View File

@@ -59,9 +59,6 @@ func _create_dock_panel() -> Control:
graph_edit = _create_graph_edit()
main_vbox.add_child(graph_edit)
# Set up preview system
_setup_preview_system()
# Set up undo/redo system
_setup_undo_redo_system()
@@ -114,12 +111,6 @@ func _create_toolbar() -> Control:
var separator2 = VSeparator.new()
toolbar.add_child(separator2)
# Preview button
var preview_button = Button.new()
preview_button.text = "Preview"
preview_button.icon = get_editor_interface().get_base_control().get_theme_icon("Play", "EditorIcons")
preview_button.connect("pressed", _on_preview_pressed)
toolbar.add_child(preview_button)
return toolbar
@@ -149,10 +140,6 @@ func _create_graph_edit() -> GraphEdit:
return graph
func _setup_preview_system() -> void:
# Set up the preview system
if graph_edit:
graph_edit.setup_preview()
func _setup_undo_redo_system() -> void:
# Set up the undo/redo system
@@ -209,7 +196,3 @@ func _on_undo_pressed() -> void:
func _on_redo_pressed() -> void:
if graph_edit:
graph_edit.redo()
func _on_preview_pressed() -> void:
if graph_edit:
graph_edit.start_preview()

0
addons/cutscene_editor/README.md Normal file → Executable file
View File

63
addons/cutscene_editor/editor/CutsceneGenerator.gd Normal file → Executable file
View File

@@ -9,7 +9,7 @@ var graph_nodes: Dictionary = {} # Map of node IDs to node data
var connections: Array = [] # List of connection data
# Generate a cutscene from graph data
func generate_cutscene(cutscene_resource: CutsceneResource) -> CutsceneManager:
func generate_cutscene(scene: Node, cutscene_resource: CutsceneResource) -> CutsceneManager:
# Clear previous data
graph_nodes.clear()
connections.clear()
@@ -30,7 +30,7 @@ func generate_cutscene(cutscene_resource: CutsceneResource) -> CutsceneManager:
return cutscene_manager
# Build action sequence starting from entry node
_build_action_sequence(entry_node, cutscene_manager)
_build_action_sequence(scene, entry_node, cutscene_manager)
return cutscene_manager
@@ -43,45 +43,42 @@ func _find_entry_node() -> Dictionary:
return {}
# Build action sequence from graph data
func _build_action_sequence(start_node: Dictionary, cutscene_manager: CutsceneManager) -> void:
# Use a queue-based traversal to process nodes in order
var node_queue = []
var processed_nodes = {}
var next_connections = _get_outgoing_connections(start_node["id"])
func _build_action_sequence(scene: Node, start_node: Dictionary, cutscene_manager: CutsceneManager) -> void:
# First pass: Create all actions
var action_map = {} # Map of node IDs to action instances
# Add initial connections to queue
for conn in next_connections:
node_queue.append(conn["to_node"])
for node_id in graph_nodes:
var node_data = graph_nodes[node_id]
# Process nodes in order
while not node_queue.is_empty():
var current_node_id = node_queue.pop_front()
# Skip if already processed
if processed_nodes.has(current_node_id):
continue
# Mark as processed
processed_nodes[current_node_id] = true
# Get node data
var node_data = graph_nodes.get(current_node_id, {})
if node_data.is_empty():
# Skip entry and exit nodes as they don't create actions
if node_data["type"] == "entry" or node_data["type"] == "exit":
continue
# Create action for regular nodes
var action = _create_action_from_node(node_data)
var action = _create_action_from_node(scene, node_data)
if action:
cutscene_manager.add_action(action)
action_map[node_id] = action
# Add next nodes to queue
var outgoing_connections = _get_outgoing_connections(current_node_id)
for conn in outgoing_connections:
if not processed_nodes.has(conn["to_node"]):
node_queue.append(conn["to_node"])
# Second pass: Add actions with their dependencies
for node_id in action_map:
print("setting up", node_id)
var action = action_map[node_id]
# Get dependencies (incoming connections)
var deps = []
var incoming_connections = _get_incoming_connections(node_id)
for conn in incoming_connections:
# Only add as dependency if the source node creates an action
var from_node_data = graph_nodes.get(conn["from_node"], {})
if not from_node_data.is_empty() and from_node_data["type"] != "entry":
deps.append(conn["from_node"])
# Add action with dependencies
cutscene_manager.add_action(node_id, action, deps)
# Create an action instance from node data
func _create_action_from_node(node_data: Dictionary):
func _create_action_from_node(scene: Node, node_data: Dictionary):
var parameters = node_data["parameters"]
match node_data["type"]:
@@ -93,7 +90,7 @@ func _create_action_from_node(node_data: Dictionary):
# In a real implementation, we would resolve the character path to an actual node
# For now, we'll create a placeholder
var character_node = null # This would be resolved at runtime
var character_node = scene.find_child(character_path) # This would be resolved at runtime
var target_position = Vector2(target_x, target_y)
return MoveAction.new(character_node, target_position, speed)

50
addons/cutscene_editor/editor/CutsceneGraphEdit.gd Normal file → Executable file
View File

@@ -16,9 +16,6 @@ var node_counter: int = 0 # For generating unique node IDs
var current_cutscene: CutsceneResource # The cutscene being edited
# Preview properties
var preview_manager: PreviewManager
var preview_panel: PreviewPanel
# Undo/Redo properties
var undo_redo_manager: UndoRedoManager
@@ -289,7 +286,7 @@ func _on_graph_node_deleted(node: BaseGraphNode) -> void:
# Remove all connections to/from this node
var connections = get_connection_list()
for connection in connections:
if connection["from_node"] == node.node_id or connection["to_node"] == node.node_id:
if connection["from_node"] == node.name or connection["to_node"] == node.name:
disconnect_node(connection["from_node"], connection["from_port"], connection["to_node"], connection["to_port"])
@@ -332,6 +329,9 @@ func clear_graph() -> void:
# Emit signal
emit_signal("graph_changed")
func get_graph_node_by_id(id: String):
return find_child(id)
# Load graph from cutscene resource
func load_from_cutscene(cutscene: CutsceneResource) -> void:
# Clear existing graph
@@ -343,14 +343,16 @@ func load_from_cutscene(cutscene: CutsceneResource) -> void:
# Create nodes from cutscene data
for node_data in cutscene.nodes:
var node = add_node(node_data["type"], Vector2(node_data["position"]["x"], node_data["position"]["y"]))
node.owner=self
if node:
node.node_id = node_data["id"]
node.name = node_data["id"]
# Set node parameters
for param_name in node_data["parameters"]:
node.set_parameter(param_name, node_data["parameters"][param_name])
# Create connections from cutscene data
for connection_data in cutscene.connections:
print(get_graph_node_by_id(connection_data["from_node"]))
connect_node(connection_data["from_node"], connection_data["from_port"],
connection_data["to_node"], connection_data["to_port"])
@@ -370,7 +372,7 @@ func save_to_cutscene() -> CutsceneResource:
for child in get_children():
if child is BaseGraphNode:
var node_data = {
"id": child.node_id,
"id": str(child.name),
"type": child.node_type,
"position": {
"x": child.position_offset.x,
@@ -384,9 +386,9 @@ func save_to_cutscene() -> CutsceneResource:
for connection in get_connection_list():
var connection_data = {
"id": _generate_unique_connection_id(),
"from_node": connection["from_node"],
"from_node": str(connection["from_node"]),
"from_port": connection["from_port"],
"to_node": connection["to_node"],
"to_node": str(connection["to_node"]),
"to_port": connection["to_port"]
}
current_cutscene.connections.append(connection_data)
@@ -398,39 +400,7 @@ func _generate_unique_connection_id() -> String:
return "conn_" + str(Time.get_ticks_msec())
# Set up preview system
func setup_preview() -> void:
# Create preview manager
preview_manager = PreviewManager.new()
add_child(preview_manager)
# Create preview panel
preview_panel = PreviewPanel.new()
preview_panel.set_preview_manager(preview_manager)
preview_panel.set_graph_edit(self)
# Add to editor interface (this would be added to the editor UI)
# For now, we'll just keep a reference to it
# Start preview
func start_preview() -> void:
if preview_manager:
preview_manager.start_preview()
# Stop preview
func stop_preview() -> void:
if preview_manager:
preview_manager.stop_preview()
# Pause preview
func pause_preview() -> void:
if preview_manager:
preview_manager.pause_preview()
# Resume preview
func resume_preview() -> void:
if preview_manager:
preview_manager.resume_preview()
# Set up undo/redo system
func _setup_undo_redo() -> void:

View File

@@ -1,274 +0,0 @@
@tool
class_name PreviewManager
extends Node
# Manager for real-time cutscene preview
# Signals
signal preview_started()
signal preview_stopped()
signal preview_paused()
signal preview_resumed()
signal preview_progress(progress: float)
signal node_activated(node_name: String)
signal node_completed(node_name: String)
# Properties
var is_previewing: bool = false
var is_paused: bool = false
var current_cutscene: CutsceneManager
var preview_scene: Node2D # The scene being previewed
var preview_characters: Dictionary = {} # Map of character names to nodes
var graph_edit: CutsceneGraphEdit # Reference to the graph editor
# Preview settings
var preview_speed: float = 1.0
var show_debug_info: bool = true
# Initialize the preview manager
func _init() -> void:
name = "PreviewManager"
# Set up the preview with a graph editor
func setup_preview(graph: CutsceneGraphEdit) -> void:
graph_edit = graph
# Connect to graph change signals
if graph_edit:
graph_edit.connect("graph_changed", _on_graph_changed)
# Start the preview
func start_preview() -> void:
if is_previewing:
return
# Create preview scene
_setup_preview_scene()
# Generate cutscene from current graph
var cutscene_resource = graph_edit.save_to_cutscene()
var generator = CutsceneGenerator.new()
current_cutscene = generator.generate_cutscene(cutscene_resource)
# Add cutscene to preview scene
if preview_scene and current_cutscene:
preview_scene.add_child(current_cutscene)
# Connect to cutscene signals for feedback
_connect_cutscene_signals()
# Start the cutscene
current_cutscene.start()
# Update state
is_previewing = true
is_paused = false
emit_signal("preview_started")
# Stop the preview
func stop_preview() -> void:
if not is_previewing:
return
# Stop the cutscene
if current_cutscene:
current_cutscene.stop()
_disconnect_cutscene_signals()
# Remove from preview scene
if current_cutscene.get_parent() == preview_scene:
preview_scene.remove_child(current_cutscene)
current_cutscene.queue_free()
# Clean up preview scene
_cleanup_preview_scene()
# Update state
is_previewing = false
is_paused = false
emit_signal("preview_stopped")
# Pause the preview
func pause_preview() -> void:
if not is_previewing or is_paused:
return
if current_cutscene:
current_cutscene.pause()
is_paused = true
emit_signal("preview_paused")
# Resume the preview
func resume_preview() -> void:
if not is_previewing or not is_paused:
return
if current_cutscene:
current_cutscene.resume()
is_paused = false
emit_signal("preview_resumed")
# Set preview speed
func set_preview_speed(speed: float) -> void:
preview_speed = speed
# In a real implementation, this would affect the time scale
# of the preview scene
# Set up the preview scene
func _setup_preview_scene() -> void:
# Create or reuse preview scene
if not preview_scene:
preview_scene = Node2D.new()
preview_scene.name = "PreviewScene"
add_child(preview_scene)
# Set up characters for preview
_setup_preview_characters()
# Set up characters for preview
func _setup_preview_characters() -> void:
# Clear existing characters
preview_characters.clear()
# Create placeholder characters for preview
# In a real implementation, this would load actual character scenes
var character1 = _create_preview_character("Character1", Vector2(100, 100))
var character2 = _create_preview_character("Character2", Vector2(200, 100))
preview_characters["Character1"] = character1
preview_characters["Character2"] = character2
# Add to preview scene
if preview_scene:
preview_scene.add_child(character1)
preview_scene.add_child(character2)
# Create a preview character
func _create_preview_character(name: String, position: Vector2) -> Node2D:
var character = Node2D.new()
character.name = name
character.position = position
# Add a visual representation
var sprite = Polygon2D.new()
sprite.polygon = PackedVector2Array([
Vector2(-10, -20),
Vector2(-30, 0),
Vector2(-10, 20),
Vector2(10, 20),
Vector2(30, 0),
Vector2(10, -20)
])
sprite.color = Color(0.5, 0.7, 1.0)
character.add_child(sprite)
return character
# Clean up the preview scene
func _cleanup_preview_scene() -> void:
# Remove characters
for char_name in preview_characters:
var character = preview_characters[char_name]
if character.get_parent() == preview_scene:
preview_scene.remove_child(character)
character.queue_free()
preview_characters.clear()
# Connect to cutscene signals for feedback
func _connect_cutscene_signals() -> void:
if not current_cutscene:
return
# Disconnect existing connections
_disconnect_cutscene_signals()
# Connect to signals
current_cutscene.connect("cutscene_started", _on_cutscene_started)
current_cutscene.connect("cutscene_completed", _on_cutscene_completed)
current_cutscene.connect("cutscene_paused", _on_cutscene_paused)
current_cutscene.connect("cutscene_resumed", _on_cutscene_resumed)
current_cutscene.connect("action_started", _on_action_started)
current_cutscene.connect("action_completed", _on_action_completed)
# Disconnect from cutscene signals
func _disconnect_cutscene_signals() -> void:
if not current_cutscene:
return
if current_cutscene.is_connected("cutscene_started", _on_cutscene_started):
current_cutscene.disconnect("cutscene_started", _on_cutscene_started)
if current_cutscene.is_connected("cutscene_completed", _on_cutscene_completed):
current_cutscene.disconnect("cutscene_completed", _on_cutscene_completed)
if current_cutscene.is_connected("cutscene_paused", _on_cutscene_paused):
current_cutscene.disconnect("cutscene_paused", _on_cutscene_paused)
if current_cutscene.is_connected("cutscene_resumed", _on_cutscene_resumed):
current_cutscene.disconnect("cutscene_resumed", _on_cutscene_resumed)
if current_cutscene.is_connected("action_started", _on_action_started):
current_cutscene.disconnect("action_started", _on_action_started)
if current_cutscene.is_connected("action_completed", _on_action_completed):
current_cutscene.disconnect("action_completed", _on_action_completed)
# Handle graph changes
func _on_graph_changed() -> void:
# If we're previewing, restart the preview to reflect changes
if is_previewing:
stop_preview()
start_preview()
# Handle cutscene started
func _on_cutscene_started() -> void:
emit_signal("preview_started")
# Handle cutscene completed
func _on_cutscene_completed() -> void:
emit_signal("preview_stopped")
is_previewing = false
is_paused = false
# Handle cutscene paused
func _on_cutscene_paused() -> void:
emit_signal("preview_paused")
is_paused = true
# Handle cutscene resumed
func _on_cutscene_resumed() -> void:
emit_signal("preview_resumed")
is_paused = false
# Handle action started
func _on_action_started(action: Action) -> void:
# Find the corresponding node in the graph and highlight it
var node_name = _find_node_for_action(action)
if node_name:
emit_signal("node_activated", node_name)
# Update graph editor visualization
if graph_edit:
var node = graph_edit.get_node_or_null(node_name)
if node and node.has_method("set_state"):
node.set_state(BaseGraphNode.NodeState.ACTIVE)
# Handle action completed
func _on_action_completed(action: Action) -> void:
# Find the corresponding node in the graph and mark as completed
var node_name = _find_node_for_action(action)
if node_name:
emit_signal("node_completed", node_name)
# Update graph editor visualization
if graph_edit:
var node = graph_edit.get_node_or_null(node_name)
if node and node.has_method("set_state"):
node.set_state(BaseGraphNode.NodeState.COMPLETED)
# Find node corresponding to an action
func _find_node_for_action(action: Action) -> String:
# This would need to map actions to nodes
# In a real implementation, we would store this mapping when generating the cutscene
# For now, we'll return a placeholder
return ""
# Get the preview scene for display
func get_preview_scene() -> Node2D:
return preview_scene

View File

@@ -1,186 +0,0 @@
@tool
class_name PreviewPanel
extends PanelContainer
# UI panel for displaying the preview
# UI elements
var preview_viewport: SubViewport
var preview_texture: TextureRect
var controls_container: HBoxContainer
var play_button: Button
var pause_button: Button
var stop_button: Button
var speed_slider: HSlider
var progress_bar: ProgressBar
var debug_label: Label
# Properties
var preview_manager: PreviewManager
var is_playing: bool = false
# Initialize the preview panel
func _ready() -> void:
_setup_ui()
_setup_signals()
# Set up the UI
func _setup_ui() -> void:
# Main container
var main_vbox = VBoxContainer.new()
main_vbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
main_vbox.size_flags_vertical = Control.SIZE_EXPAND_FILL
add_child(main_vbox)
# Preview viewport
var viewport_container = AspectRatioContainer.new()
viewport_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
viewport_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
viewport_container.ratio = 16.0/9.0
main_vbox.add_child(viewport_container)
preview_viewport = SubViewport.new()
preview_viewport.size = Vector2i(800, 450)
preview_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
viewport_container.add_child(preview_viewport)
preview_texture = TextureRect.new()
preview_texture.expand = true
preview_texture.size_flags_horizontal = Control.SIZE_EXPAND_FILL
preview_texture.size_flags_vertical = Control.SIZE_EXPAND_FILL
preview_texture.texture = preview_viewport.get_texture()
viewport_container.add_child(preview_texture)
# Controls
controls_container = HBoxContainer.new()
controls_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
main_vbox.add_child(controls_container)
play_button = Button.new()
play_button.text = ""
play_button.flat = true
controls_container.add_child(play_button)
pause_button = Button.new()
pause_button.text = ""
pause_button.flat = true
controls_container.add_child(pause_button)
stop_button = Button.new()
stop_button.text = ""
stop_button.flat = true
controls_container.add_child(stop_button)
var speed_label = Label.new()
speed_label.text = "Speed:"
controls_container.add_child(speed_label)
speed_slider = HSlider.new()
speed_slider.min = 0.1
speed_slider.max = 2.0
speed_slider.step = 0.1
speed_slider.value = 1.0
speed_slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
controls_container.add_child(speed_slider)
# Progress bar
progress_bar = ProgressBar.new()
progress_bar.size_flags_horizontal = Control.SIZE_EXPAND_FILL
progress_bar.percent_visible = true
main_vbox.add_child(progress_bar)
# Debug info
debug_label = Label.new()
debug_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
main_vbox.add_child(debug_label)
# Set up signal connections
func _setup_signals() -> void:
play_button.connect("pressed", _on_play_pressed)
pause_button.connect("pressed", _on_pause_pressed)
stop_button.connect("pressed", _on_stop_pressed)
speed_slider.connect("value_changed", _on_speed_changed)
# Set the preview manager
func set_preview_manager(manager: PreviewManager) -> void:
preview_manager = manager
# Connect to preview manager signals
if preview_manager:
preview_manager.connect("preview_started", _on_preview_started)
preview_manager.connect("preview_stopped", _on_preview_stopped)
preview_manager.connect("preview_paused", _on_preview_paused)
preview_manager.connect("preview_resumed", _on_preview_resumed)
preview_manager.connect("preview_progress", _on_preview_progress)
preview_manager.connect("node_activated", _on_node_activated)
preview_manager.connect("node_completed", _on_node_completed)
# Set the graph editor
func set_graph_edit(graph_edit: CutsceneGraphEdit) -> void:
if preview_manager:
preview_manager.setup_preview(graph_edit)
# Add preview scene to viewport
var preview_scene = preview_manager.get_preview_scene()
if preview_scene and preview_scene.get_parent() != preview_viewport:
preview_viewport.add_child(preview_scene)
# Handle play button press
func _on_play_pressed() -> void:
if preview_manager:
if is_playing:
preview_manager.resume_preview()
else:
preview_manager.start_preview()
# Handle pause button press
func _on_pause_pressed() -> void:
if preview_manager:
preview_manager.pause_preview()
# Handle stop button press
func _on_stop_pressed() -> void:
if preview_manager:
preview_manager.stop_preview()
# Handle speed slider change
func _on_speed_changed(value: float) -> void:
if preview_manager:
preview_manager.set_preview_speed(value)
# Handle preview started
func _on_preview_started() -> void:
is_playing = true
play_button.text = ""
debug_label.text = "Preview started"
# Handle preview stopped
func _on_preview_stopped() -> void:
is_playing = false
play_button.text = ""
progress_bar.value = 0
debug_label.text = "Preview stopped"
# Handle preview paused
func _on_preview_paused() -> void:
is_playing = false
play_button.text = ""
debug_label.text = "Preview paused"
# Handle preview resumed
func _on_preview_resumed() -> void:
is_playing = true
play_button.text = ""
debug_label.text = "Preview resumed"
# Handle preview progress
func _on_preview_progress(progress: float) -> void:
progress_bar.value = progress * 100
# Handle node activated
func _on_node_activated(node_name: String) -> void:
debug_label.text = "Executing: %s" % node_name
# Handle node completed
func _on_node_completed(node_name: String) -> void:
debug_label.text = "Completed: %s" % node_name

0
addons/cutscene_editor/editor/UndoRedoManager.gd Normal file → Executable file
View File

View File

@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
func _init() -> void:
node_type = "animation"
node_id = "animation_" + str(randi())
name = "animation_" + str(randi())
title = "Animation"
modulate = Color(0.8, 0.4, 0.8) # Purple

View File

2
addons/cutscene_editor/editor/nodes/BaseGraphNode.gd Normal file → Executable file
View File

@@ -20,7 +20,7 @@ enum NodeState {
# Properties
var node_type: String = "base"
var node_id: String # Unique identifier for the node
var action_parameters: Dictionary = {} # Stores parameter values
var current_state: int = NodeState.IDLE
var error_message: String = ""

View File

@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
func _init() -> void:
node_type = "dialogue"
node_id = "dialogue_" + str(randi())
name = "dialogue_" + str(randi())
title = "Dialogue"
modulate = Color(1.0, 1.0, 0.5) # Yellow
resizable=true

View File

2
addons/cutscene_editor/editor/nodes/EntryNode.gd Normal file → Executable file
View File

@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
func _init() -> void:
node_type = "entry"
node_id = "entry_" + str(randi())
name = "entry_" + str(randi())
title = "Start"
modulate = Color(0.5, 1.0, 0.5) # Light green

12
addons/cutscene_editor/editor/nodes/EntryNode.tscn Normal file → Executable file
View File

@@ -1,15 +1,23 @@
[gd_scene load_steps=2 format=3 uid="uid://entrynodetscn"]
[gd_scene load_steps=2 format=3 uid="uid://sfwelq3tmwkv"]
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/EntryNode.gd" id="1_entry"]
[node name="EntryNode" type="GraphNode"]
modulate = Color(0.5, 1.0, 0.5, 1)
modulate = Color(0.5, 1, 0.5, 1)
custom_minimum_size = Vector2(100, 0)
title = "Start"
slot/0/left_enabled = false
slot/0/left_type = 0
slot/0/left_color = Color(0, 0, 0, 0)
slot/0/left_icon = null
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color(0, 0, 0, 1)
slot/0/right_icon = null
slot/0/draw_stylebox = true
script = ExtResource("1_entry")
[node name="Label" type="Label" parent="."]
layout_mode = 2
text = "completed
"

2
addons/cutscene_editor/editor/nodes/ExitNode.gd Normal file → Executable file
View File

@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
func _init() -> void:
node_type = "exit"
node_id = "exit_" + str(randi())
name = "exit_" + str(randi())
title = "End"
modulate = Color(1.0, 0.5, 0.5) # Light red

10
addons/cutscene_editor/editor/nodes/ExitNode.tscn Normal file → Executable file
View File

@@ -1,14 +1,22 @@
[gd_scene load_steps=2 format=3 uid="uid://exitnodetscn"]
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/ExitNode.gd" id="1_exit"]
[node name="ExitNode" type="GraphNode"]
modulate = Color(1.0, 0.5, 0.5, 1)
modulate = Color(1, 0.5, 0.5, 1)
custom_minimum_size = Vector2(100, 0)
title = "End"
slot/0/left_enabled = true
slot/0/left_type = 0
slot/0/left_color = Color(0, 0, 0, 1)
slot/0/left_icon = null
slot/0/right_enabled = false
slot/0/right_type = 0
slot/0/right_color = Color(0, 0, 0, 0)
slot/0/right_icon = null
slot/0/draw_stylebox = true
script = ExtResource("1_exit")
[node name="Label" type="Label" parent="."]
layout_mode = 2
text = "Dependency"

12
addons/cutscene_editor/editor/nodes/MoveActionNode.gd Normal file → Executable file
View File

@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
func _init() -> void:
node_type = "move"
node_id = "move_" + str(randi())
name = "move_" + str(randi())
title = "Move"
modulate = Color(0.4, 0.6, 1.0) # Blue
@@ -22,6 +22,16 @@ func _ready() -> void:
action_parameters["target_y"] = 0.0
action_parameters["speed"] = 100.0
func set_parameter(pname, value) -> void:
super.set_parameter(name, value)
if pname == "character":
$VBoxContainer/CharacterEDit.text = value
elif pname == "target_x":
$VBoxContainer/HBoxContainer/x.text = value
elif pname == "target_y":
$VBoxContainer/HBoxContainer/y.text = value
elif pname == "speed":
$VBoxContainer/speed.text = value
func _on_character_changed(new_text: String) -> void:
set_parameter("character", new_text)

View File

@@ -23,7 +23,7 @@ layout_mode = 2
[node name="Character" type="Label" parent="VBoxContainer"]
layout_mode = 2
[node name="TextEdit" type="LineEdit" parent="VBoxContainer"]
[node name="CharacterEDit" type="LineEdit" parent="VBoxContainer"]
custom_minimum_size = Vector2(0, 32.865)
layout_mode = 2
text = "aoeu"
@@ -49,7 +49,7 @@ text = "Speed"
[node name="speed" type="LineEdit" parent="VBoxContainer"]
layout_mode = 2
[connection signal="text_changed" from="VBoxContainer/TextEdit" to="." method="_on_character_changed"]
[connection signal="text_changed" from="VBoxContainer/CharacterEDit" to="." method="_on_character_changed"]
[connection signal="text_changed" from="VBoxContainer/HBoxContainer/x" to="." method="_on_target_x_changed"]
[connection signal="text_changed" from="VBoxContainer/HBoxContainer/y" to="." method="_on_target_y_changed"]
[connection signal="text_change_rejected" from="VBoxContainer/speed" to="." method="_on_speed_text_change_rejected"]

View File

@@ -14,7 +14,7 @@ var container_rect: PanelContainer # Visual container for child nodes
func _init() -> void:
node_type = "parallel"
node_id = "parallel_" + str(randi())
name = "parallel_" + str(randi())
title = "Parallel Group"
modulate = Color(1.0, 0.6, 0.2) # Orange

2
addons/cutscene_editor/editor/nodes/TurnActionNode.gd Normal file → Executable file
View File

@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
func _init() -> void:
node_type = "turn"
node_id = "turn_" + str(randi())
name = "turn_" + str(randi())
title = "Turn"
modulate = Color(0.5, 1.0, 0.5) # Green

View File

0
addons/cutscene_editor/editor/nodes/WaitActionNode.gd Normal file → Executable file
View File

View File

View File

0
addons/cutscene_editor/icons/icon_animation.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 357 B

After

Width:  |  Height:  |  Size: 357 B

0
addons/cutscene_editor/icons/icon_animation.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_dialogue.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 337 B

0
addons/cutscene_editor/icons/icon_dialogue.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_entry.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 222 B

0
addons/cutscene_editor/icons/icon_entry.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_exit.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 244 B

0
addons/cutscene_editor/icons/icon_exit.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_move.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 383 B

0
addons/cutscene_editor/icons/icon_move.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_parallel.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 428 B

After

Width:  |  Height:  |  Size: 428 B

0
addons/cutscene_editor/icons/icon_parallel.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_turn.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 335 B

0
addons/cutscene_editor/icons/icon_turn.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/icons/icon_wait.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 407 B

After

Width:  |  Height:  |  Size: 407 B

0
addons/cutscene_editor/icons/icon_wait.svg.import Normal file → Executable file
View File

0
addons/cutscene_editor/plugin.cfg Normal file → Executable file
View File

0
addons/cutscene_editor/tests/test_cutscene_resource.gd Normal file → Executable file
View File

View File

0
cutscene/Action.gd Normal file → Executable file
View File

186
cutscene/CutsceneManager.gd Normal file → Executable file
View File

@@ -1,14 +1,13 @@
class_name CutsceneManager
extends Node
# Action queues
var sequential_actions: Array = [] # Actions that run one after another
var current_action: Action = null # The action currently being executed
var action_index: int = 0 # Index of the next sequential action
# Parallel actions
var parallel_groups: Array = [] # Groups of actions running simultaneously
var active_parallel_groups: Array = [] # Currently running parallel action groups
# Action dependency graph
var actions: Dictionary = {} # Map of action IDs to action instances
var dependencies: Dictionary = {} # Map of action IDs to their dependency lists
var dependents: Dictionary = {} # Map of action IDs to actions that depend on them
var ready_actions: Array = [] # Actions that are ready to execute (all dependencies met)
var active_actions: Array = [] # Currently running actions
var completed_actions: Array = [] # Actions that have completed
# State management
enum State {
@@ -39,8 +38,16 @@ func start() -> void:
is_active = true
emit_signal("cutscene_started")
# Start first action
_execute_next_action()
# Find actions with no dependencies to start with
_find_ready_actions()
# Start all ready actions
for action_id in ready_actions:
_execute_action(action_id)
# Check if there are no actions to execute
if actions.size() == 0:
_on_cutscene_completed()
func pause() -> void:
# Pause the current cutscene
@@ -56,67 +63,78 @@ func resume() -> void:
func stop() -> void:
# Stop the current cutscene and reset
if current_action != null:
current_action.stop()
current_action = null
# Stop all active parallel groups
for group in active_parallel_groups:
for action in group["actions"]:
# Stop all active actions
for action in active_actions:
if action.state == action.State.RUNNING:
action.stop()
active_actions.clear()
_reset()
func add_action(action: Action) -> void:
# Add a single action to the sequential queue
func add_action(action_id: String, action: Action, deps: Array = []) -> void:
# Add an action with its dependencies
if state != State.IDLE:
print("Warning: Cannot add actions while cutscene is running")
return
sequential_actions.append(action)
actions[action_id] = action
dependencies[action_id] = deps
# Build reverse dependency map (dependents)
for dep_id in deps:
if not dependents.has(dep_id):
dependents[dep_id] = []
dependents[dep_id].append(action_id)
# Internal methods
func _process(delta: float) -> void:
# Main update loop
if state != State.RUNNING:
return
# Find actions with no dependencies to start with
_find_ready_actions()
# Update current sequential action
if current_action != null and current_action.state == current_action.State.RUNNING:
current_action.update(delta)
# Start all ready actions
for action_id in ready_actions:
_execute_action(action_id)
# Update active parallel groups
for group in active_parallel_groups:
for action in group["actions"]:
# Update all active actions
for action in active_actions:
if action.state == action.State.RUNNING:
action.update(delta)
func _execute_next_action() -> void:
# Start executing the next sequential action
if action_index >= sequential_actions.size():
# No more actions, cutscene complete
_on_cutscene_completed()
return
func _find_ready_actions() -> void:
# Find actions that are ready to execute (all dependencies met)
ready_actions.clear()
var action_item = sequential_actions[action_index]
action_index += 1
print(action_item)
# Check if this is a parallel group or single action
if typeof(action_item) == TYPE_DICTIONARY and action_item.has("actions"):
# This is a parallel group
_execute_parallel_group(action_item)
else:
# This is a single action
_execute_single_action(action_item)
for action_id in actions:
# Skip if already completed or active
if completed_actions.has(action_id) or active_actions.has(actions[action_id]):
continue
func _execute_single_action(action: Action) -> void:
# Check if all dependencies are met
var all_deps_met = true
for dep_id in dependencies[action_id]:
if not completed_actions.has(dep_id):
all_deps_met = false
break
if all_deps_met:
ready_actions.append(action_id)
func _execute_action(action_id: String) -> void:
# Execute a single action
current_action = action
var action = actions[action_id]
# Remove from ready actions
ready_actions.erase(action_id)
# Add to active actions
active_actions.append(action)
# Connect to action signals
if not action.is_connected("completed", _on_action_completed):
action.connect("completed", _on_action_completed.bind(action))
action.connect("completed", _on_action_completed.bind(action_id))
if not action.is_connected("failed", _on_action_failed):
action.connect("failed", _on_action_failed.bind(action))
if not action.is_connected("started", _on_action_started):
@@ -126,72 +144,37 @@ func _execute_single_action(action: Action) -> void:
emit_signal("action_started", action)
action.start()
func _execute_parallel_group(group: Dictionary) -> void:
# Execute a group of parallel actions
var actions = group["actions"]
# Reset completion count
group["completed_count"] = 0
# Add to active parallel groups
active_parallel_groups.append(group)
# Connect to each action's signals
for action in actions:
if not action.is_connected("completed", _on_parallel_action_completed):
action.connect("completed", _on_parallel_action_completed.bind(group, action))
if not action.is_connected("failed", _on_parallel_action_failed):
action.connect("failed", _on_parallel_action_failed.bind(group, action))
if not action.is_connected("started", _on_action_started):
action.connect("started", _on_action_started.bind(action))
# Emit started signal and start action
emit_signal("action_started", action)
action.start()
func _on_action_started(action: Action) -> void:
# Handle action started
emit_signal("action_started", action)
func _on_action_completed(action: Action) -> void:
func _on_action_completed(action_id: String) -> void:
# Handle action completion
if action == current_action:
current_action = null
var action = actions[action_id]
active_actions.erase(action)
completed_actions.append(action_id)
emit_signal("action_completed", action)
# Move to next action
_execute_next_action()
# Check if all actions are completed
if completed_actions.size() == actions.size():
_on_cutscene_completed()
else:
# Find newly ready actions
_find_ready_actions()
# Start all newly ready actions
for new_action_id in ready_actions:
_execute_action(new_action_id)
func _on_action_failed(action: Action, error_message: String) -> void:
# Handle action failure
if action == current_action:
current_action = null
active_actions.erase(action)
emit_signal("action_failed", action, error_message)
print("Action failed: %s - %s" % [action.name, error_message])
# Stop the cutscene
stop()
func _on_parallel_action_completed(group: Dictionary, action: Action) -> void:
# Increment completed count
group["completed_count"] += 1
emit_signal("action_completed", action)
# Check if all actions in group are completed
if group["completed_count"] >= group["total_count"]:
# Remove from active groups
active_parallel_groups.erase(group)
# Continue with next sequential action
_execute_next_action()
func _on_parallel_action_failed(group: Dictionary, action: Action, error_message: String) -> void:
# Handle parallel action failure
emit_signal("action_failed", action, error_message)
print("Parallel action failed: %s - %s" % [action.name, error_message])
# Stop the cutscene
stop()
func _on_cutscene_completed() -> void:
# Handle cutscene completion
state = State.IDLE
@@ -200,10 +183,11 @@ func _on_cutscene_completed() -> void:
func _reset() -> void:
# Reset the manager to initial state
sequential_actions.clear()
parallel_groups.clear()
active_parallel_groups.clear()
current_action = null
action_index = 0
actions.clear()
dependencies.clear()
dependents.clear()
ready_actions.clear()
active_actions.clear()
completed_actions.clear()
state = State.IDLE
is_active = false

0
cutscene/README.md Normal file → Executable file
View File

0
cutscene/actions/AnimationAction.gd Normal file → Executable file
View File

0
cutscene/actions/DialogueAction.gd Normal file → Executable file
View File

1
cutscene/actions/MoveAction.gd Normal file → Executable file
View File

@@ -30,7 +30,6 @@ func start() -> void:
self._set_running()
func update(delta: float) -> void:
print ("updating")
if state != State.RUNNING:
return

0
cutscene/actions/TurnAction.gd Normal file → Executable file
View File

0
cutscene/actions/WaitAction.gd Normal file → Executable file
View File

2
example_cutscene.tscn Normal file → Executable file
View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=2 format=3 uid="uid://bi4gojo71c7jt"]
[gd_scene load_steps=2 format=3 uid="uid://bi2c4ph8txa4y"]
[sub_resource type="GDScript" id="GDScript_e7tbc"]
script/source = "extends Node2D

View File

@@ -1,34 +0,0 @@
[gd_resource type="Resource" script_class="CutsceneResource" load_steps=2 format=3 uid="uid://ci8lt4jyxcysx"]
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/resources/CutsceneResource.gd" id="1_as4bh"]
[resource]
script = ExtResource("1_as4bh")
nodes = [{
"id": "entry_1227949280",
"parameters": {},
"position": {
"x": 300.0,
"y": 160.0
},
"type": "entry"
}, {
"id": "move_3555857962",
"parameters": {
"character": "",
"speed": 100.0,
"target_x": 0.0,
"target_y": 0.0
},
"position": {
"x": 763.0,
"y": 168.0
},
"type": "move"
}]
connections = []
metadata = {
"created": 1.75399e+09,
"modified": 1.75399e+09,
"version": "2.0"
}

0
icon.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 994 B

0
icon.svg.import Normal file → Executable file
View File

0
main.tscn Normal file → Executable file
View File

0
plans/cutscene_data_structure.md Normal file → Executable file
View File

0
plans/cutscene_documentation_plan.md Normal file → Executable file
View File

0
plans/cutscene_generator_changes.md Normal file → Executable file
View File

0
plans/cutscene_graph_edit_changes.md Normal file → Executable file
View File

0
plans/cutscene_resource_analysis.md Normal file → Executable file
View File

0
plans/cutscene_resource_implementation.md Normal file → Executable file
View File

0
plans/cutscene_resource_implementation_summary.md Normal file → Executable file
View File

0
plans/cutscene_test_plan.md Normal file → Executable file
View File

2
project.godot Normal file → Executable file
View File

@@ -12,7 +12,7 @@ config_version=5
config/name="adventure-ai"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.3", "Forward Plus")
config/features=PackedStringArray("4.2", "Forward Plus")
config/icon="res://icon.svg"
[editor_plugins]

18
tes2265.tmp Executable file
View File

@@ -0,0 +1,18 @@
[gd_scene load_steps=2 format=3 uid="uid://vlh0eb7qn72o"]
[ext_resource type="Script" path="res://test_resource_cutscene.gd" id="1"]
[node name="Node2D" type="Node2D"]
script = ExtResource("1")
[node name="Character1" type="Node2D" parent="."]
position = Vector2(100, 100)
[node name="Polygon2D" type="Polygon2D" parent="Character1"]
polygon = PackedVector2Array(33, -74, -67, 4, -20, 33, 45, 2)
[node name="Character2" type="Node2D" parent="."]
position = Vector2(200, 200)
[node name="Polygon2D" type="Polygon2D" parent="Character2"]
polygon = PackedVector2Array(21, -54, -56, 23, 2, 59, 63, -16, 58, -69)

101
test_cutscene.tres Executable file
View File

@@ -0,0 +1,101 @@
[gd_resource type="Resource" script_class="CutsceneResource" load_steps=2 format=3 uid="uid://bfngefj7emehe"]
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/resources/CutsceneResource.gd" id="1_p6huk"]
[resource]
script = ExtResource("1_p6huk")
nodes = [{
"id": "entry_476938218",
"parameters": {},
"position": {
"x": 262.0,
"y": 155.0
},
"type": "entry"
}, {
"id": "move_3499731826",
"parameters": {
"character": "",
"move_3499731826": 700.0,
"speed": 100.0,
"target_x": 0.0,
"target_y": 0.0
},
"position": {
"x": 380.0,
"y": 40.0
},
"type": "move"
}, {
"id": "exit_1710964436",
"parameters": {},
"position": {
"x": 1020.0,
"y": 140.0
},
"type": "exit"
}, {
"id": "move_2800650428",
"parameters": {
"character": "",
"move_2800650428": 91.0,
"speed": 100.0,
"target_x": 0.0,
"target_y": 0.0
},
"position": {
"x": 640.0,
"y": 60.0
},
"type": "move"
}, {
"id": "MoveActionNode",
"parameters": {
"MoveActionNode": 50.0,
"character": "",
"speed": 100.0,
"target_x": 0.0,
"target_y": 0.0
},
"position": {
"x": 520.0,
"y": 340.0
},
"type": "move"
}]
connections = [{
"from_node": "entry_476938218",
"from_port": 0,
"id": "conn_4022396",
"to_node": "move_3499731826",
"to_port": 0
}, {
"from_node": "move_3499731826",
"from_port": 0,
"id": "conn_4022396",
"to_node": "move_2800650428",
"to_port": 0
}, {
"from_node": "move_2800650428",
"from_port": 0,
"id": "conn_4022396",
"to_node": "exit_1710964436",
"to_port": 0
}, {
"from_node": "move_3499731826",
"from_port": 0,
"id": "conn_4022396",
"to_node": "MoveActionNode",
"to_port": 0
}, {
"from_node": "MoveActionNode",
"from_port": 0,
"id": "conn_4022396",
"to_node": "exit_1710964436",
"to_port": 0
}]
metadata = {
"created": 1.75402e+09,
"modified": 1.75402e+09,
"version": "2.0"
}

234
test_cutscene2.gd Executable file
View File

@@ -0,0 +1,234 @@
extends Node2D
# Test script for the new resource-based cutscene system
# Character nodes
@onready var character1: Node2D = $Character1
@onready var character2: Node2D = $Character2
# Cutscene manager
var cutscene_manager: CutsceneManager
func _ready() -> void:
# Initialize the cutscene system
setup_cutscene()
# Start the cutscene after a short delay to see the initial positions
var start_timer = Timer.new()
start_timer.wait_time = 1.0
start_timer.one_shot = true
start_timer.connect("timeout", start_cutscene)
add_child(start_timer)
start_timer.start()
func setup_cutscene() -> void:
# Create the cutscene manager
cutscene_manager = CutsceneManager.new()
add_child(cutscene_manager)
# Connect to cutscene signals
cutscene_manager.connect("cutscene_started", _on_cutscene_started)
cutscene_manager.connect("cutscene_completed", _on_cutscene_completed)
cutscene_manager.connect("action_started", _on_action_started)
cutscene_manager.connect("action_completed", _on_action_completed)
# Create a cutscene resource with the same sequence as the original example
var cutscene_resource = preload("res://test_cutscene.tres")
# Generate actions from the resource
var generator = CutsceneGenerator.new()
cutscene_manager = generator.generate_cutscene(self, cutscene_resource)
# Add the cutscene manager to the scene
add_child(cutscene_manager)
# Connect to cutscene signals
cutscene_manager.connect("cutscene_started", _on_cutscene_started)
cutscene_manager.connect("cutscene_completed", _on_cutscene_completed)
cutscene_manager.connect("action_started", _on_action_started)
cutscene_manager.connect("action_completed", _on_action_completed)
func create_test_cutscene_resource() -> CutsceneResource:
# Create a new cutscene resource
var resource = CutsceneResource.new()
# Create nodes for the cutscene
var entry_node = {
"id": "entry_1",
"type": "entry",
"position": {"x": 100, "y": 100},
"parameters": {}
}
var move1_node = {
"id": "move_1",
"type": "move",
"position": {"x": 250, "y": 100},
"parameters": {
"character": "Character1",
"target_x": 234,
"target_y": 591,
"speed": 100.0
}
}
var move2_node = {
"id": "move_2",
"type": "move",
"position": {"x": 250, "y": 150},
"parameters": {
"character": "Character2",
"target_x": 912,
"target_y": 235,
"speed": 100.0
}
}
var turn_node = {
"id": "turn_1",
"type": "turn",
"position": {"x": 400, "y": 100},
"parameters": {
"character": "character2",
"target": "character1",
"turn_speed": 1.0
}
}
var dialogue1_node = {
"id": "dialogue_1",
"type": "dialogue",
"position": {"x": 550, "y": 100},
"parameters": {
"character": "character2",
"text": "Hello there, friend!",
"duration": 2.0
}
}
var wait_node = {
"id": "wait_1",
"type": "wait",
"position": {"x": 700, "y": 100},
"parameters": {
"duration": 1.0
}
}
var dialogue2_node = {
"id": "dialogue_2",
"type": "dialogue",
"position": {"x": 850, "y": 100},
"parameters": {
"character": "character1",
"text": "That was surprising!",
"duration": 2.0
}
}
var exit_node = {
"id": "exit_1",
"type": "exit",
"position": {"x": 1000, "y": 100},
"parameters": {}
}
# Add nodes to resource
resource.add_node(entry_node)
resource.add_node(move1_node)
resource.add_node(move2_node)
resource.add_node(turn_node)
resource.add_node(dialogue1_node)
resource.add_node(wait_node)
resource.add_node(dialogue2_node)
resource.add_node(exit_node)
# Create connections
var connections = [
{
"id": "conn_1",
"from_node": "entry_1",
"from_port": 0,
"to_node": "move_1",
"to_port": 0
},
{
"id": "conn_2",
"from_node": "entry_1",
"from_port": 0,
"to_node": "move_2",
"to_port": 0
},
{
"id": "conn_3",
"from_node": "move_1",
"from_port": 0,
"to_node": "turn_node",
"to_port": 0
},
{
"id": "conn_4",
"from_node": "move_2",
"from_port": 0,
"to_node": "turn_node",
"to_port": 0
},
{
"id": "conn_5",
"from_node": "turn_node",
"from_port": 0,
"to_node": "dialogue_1",
"to_port": 0
},
{
"id": "conn_6",
"from_node": "dialogue_1",
"from_port": 0,
"to_node": "wait_node",
"to_port": 0
},
{
"id": "conn_7",
"from_node": "wait_node",
"from_port": 0,
"to_node": "dialogue_2",
"to_port": 0
},
{
"id": "conn_8",
"from_node": "dialogue_2",
"from_port": 0,
"to_node": "exit_1",
"to_port": 0
}
]
# Add connections to resource
for conn in connections:
resource.add_connection(conn)
return resource
func start_cutscene() -> void:
print("Starting cutscene...")
cutscene_manager.start()
func _on_cutscene_started() -> void:
print("Cutscene started!")
func _on_cutscene_completed() -> void:
print("Cutscene completed!")
print("Final positions:")
print("Character1: %s" % character1.position)
print("Character2: %s" % character2.position)
func _on_action_started(action: Action) -> void:
print("Action started: %s, %s" % action.name)
func _on_action_completed(action: Action) -> void:
print("Action completed: %s, %s" % action.name)
# Clean up when the node is removed
func _exit_tree() -> void:
if cutscene_manager:
cutscene_manager.queue_free()

18
test_cutscene2.tscn Executable file
View File

@@ -0,0 +1,18 @@
[gd_scene load_steps=2 format=3 uid="uid://bb0vnntvwbuff"]
[ext_resource type="Script" path="res://test_cutscene2.gd" id="1_6nibr"]
[node name="Node2D" type="Node2D"]
script = ExtResource("1_6nibr")
[node name="Character1" type="Node2D" parent="."]
position = Vector2(100, 100)
[node name="Polygon2D" type="Polygon2D" parent="Character1"]
polygon = PackedVector2Array(33, -74, -67, 4, -20, 33, 45, 2)
[node name="Character2" type="Node2D" parent="."]
position = Vector2(200, 200)
[node name="Polygon2D" type="Polygon2D" parent="Character2"]
polygon = PackedVector2Array(21, -54, -56, 23, 2, 59, 63, -16, 58, -69)

50
test_dependency_cutscene.gd Executable file
View File

@@ -0,0 +1,50 @@
extends Node
# Test script for the new dependency-based cutscene system
func _ready():
# Create a simple test cutscene
_test_dependency_system()
func _test_dependency_system():
print("Testing dependency-based cutscene system")
# Create cutscene manager
var cutscene_manager = CutsceneManager.new()
add_child(cutscene_manager)
# Create some test actions
var wait1 = preload("res://cutscene/actions/WaitAction.gd").new(1.0)
wait1.name = "Wait1"
var wait2 = preload("res://cutscene/actions/WaitAction.gd").new(2.0)
wait2.name = "Wait2"
var wait3 = preload("res://cutscene/actions/WaitAction.gd").new(1.5)
wait3.name = "Wait3"
# Add actions with dependencies
# wait1 and wait2 can run in parallel (no dependencies)
# wait3 depends on wait1
cutscene_manager.add_action("wait1", wait1, [])
cutscene_manager.add_action("wait2", wait2, [])
cutscene_manager.add_action("wait3", wait3, ["wait1"])
# Connect to signals
cutscene_manager.connect("cutscene_completed", _on_cutscene_completed)
cutscene_manager.connect("action_started", _on_action_started)
cutscene_manager.connect("action_completed", _on_action_completed)
# Start the cutscene
cutscene_manager.start()
print("Cutscene started with dependency-based execution")
func _on_cutscene_completed():
print("Cutscene completed successfully!")
func _on_action_started(action):
print("Action started: %s" % action.name)
func _on_action_completed(action):
print("Action completed: %s" % action.name)

6
test_dependency_cutscene.tscn Executable file
View File

@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=2]
[node name="Node" type="Node"]
script = ExtResource( 1 )
[resource]

8
test_resource_cutscene.gd Normal file → Executable file
View File

@@ -37,7 +37,7 @@ func setup_cutscene() -> void:
# Generate actions from the resource
var generator = CutsceneGenerator.new()
cutscene_manager = generator.generate_cutscene(cutscene_resource)
cutscene_manager = generator.generate_cutscene(self, cutscene_resource)
# Add the cutscene manager to the scene
add_child(cutscene_manager)
@@ -77,7 +77,7 @@ func create_test_cutscene_resource() -> CutsceneResource:
"type": "move",
"position": {"x": 250, "y": 150},
"parameters": {
"character": "character2",
"character": "Character2",
"target_x": 912,
"target_y": 235,
"speed": 100.0
@@ -223,10 +223,10 @@ func _on_cutscene_completed() -> void:
print("Character2: %s" % character2.position)
func _on_action_started(action: Action) -> void:
print("Action started: %s" % action.name)
print("Action started: %s, %s" % action.name)
func _on_action_completed(action: Action) -> void:
print("Action completed: %s" % action.name)
print("Action completed: %s, %s" % action.name)
# Clean up when the node is removed
func _exit_tree() -> void:

0
test_resource_cutscene.tscn Normal file → Executable file
View File