progress
0
.gitattributes
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
addons/cutscene_editor/CHANGES.md
Normal file → Executable file
19
addons/cutscene_editor/CutsceneEditorPlugin.gd
Normal file → Executable file
@@ -59,9 +59,6 @@ func _create_dock_panel() -> Control:
|
|||||||
graph_edit = _create_graph_edit()
|
graph_edit = _create_graph_edit()
|
||||||
main_vbox.add_child(graph_edit)
|
main_vbox.add_child(graph_edit)
|
||||||
|
|
||||||
# Set up preview system
|
|
||||||
_setup_preview_system()
|
|
||||||
|
|
||||||
# Set up undo/redo system
|
# Set up undo/redo system
|
||||||
_setup_undo_redo_system()
|
_setup_undo_redo_system()
|
||||||
|
|
||||||
@@ -113,13 +110,7 @@ func _create_toolbar() -> Control:
|
|||||||
# Separator
|
# Separator
|
||||||
var separator2 = VSeparator.new()
|
var separator2 = VSeparator.new()
|
||||||
toolbar.add_child(separator2)
|
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
|
return toolbar
|
||||||
|
|
||||||
@@ -149,10 +140,6 @@ func _create_graph_edit() -> GraphEdit:
|
|||||||
|
|
||||||
return graph
|
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:
|
func _setup_undo_redo_system() -> void:
|
||||||
# Set up the undo/redo system
|
# Set up the undo/redo system
|
||||||
@@ -209,7 +196,3 @@ func _on_undo_pressed() -> void:
|
|||||||
func _on_redo_pressed() -> void:
|
func _on_redo_pressed() -> void:
|
||||||
if graph_edit:
|
if graph_edit:
|
||||||
graph_edit.redo()
|
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
63
addons/cutscene_editor/editor/CutsceneGenerator.gd
Normal file → Executable file
@@ -9,7 +9,7 @@ var graph_nodes: Dictionary = {} # Map of node IDs to node data
|
|||||||
var connections: Array = [] # List of connection data
|
var connections: Array = [] # List of connection data
|
||||||
|
|
||||||
# Generate a cutscene from graph 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
|
# Clear previous data
|
||||||
graph_nodes.clear()
|
graph_nodes.clear()
|
||||||
connections.clear()
|
connections.clear()
|
||||||
@@ -30,7 +30,7 @@ func generate_cutscene(cutscene_resource: CutsceneResource) -> CutsceneManager:
|
|||||||
return cutscene_manager
|
return cutscene_manager
|
||||||
|
|
||||||
# Build action sequence starting from entry node
|
# 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
|
return cutscene_manager
|
||||||
|
|
||||||
@@ -43,45 +43,42 @@ func _find_entry_node() -> Dictionary:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Build action sequence from graph data
|
# Build action sequence from graph data
|
||||||
func _build_action_sequence(start_node: Dictionary, cutscene_manager: CutsceneManager) -> void:
|
func _build_action_sequence(scene: Node, start_node: Dictionary, cutscene_manager: CutsceneManager) -> void:
|
||||||
# Use a queue-based traversal to process nodes in order
|
# First pass: Create all actions
|
||||||
var node_queue = []
|
var action_map = {} # Map of node IDs to action instances
|
||||||
var processed_nodes = {}
|
|
||||||
var next_connections = _get_outgoing_connections(start_node["id"])
|
|
||||||
|
|
||||||
# Add initial connections to queue
|
for node_id in graph_nodes:
|
||||||
for conn in next_connections:
|
var node_data = graph_nodes[node_id]
|
||||||
node_queue.append(conn["to_node"])
|
|
||||||
|
|
||||||
# Process nodes in order
|
|
||||||
while not node_queue.is_empty():
|
|
||||||
var current_node_id = node_queue.pop_front()
|
|
||||||
|
|
||||||
# Skip if already processed
|
# Skip entry and exit nodes as they don't create actions
|
||||||
if processed_nodes.has(current_node_id):
|
if node_data["type"] == "entry" or node_data["type"] == "exit":
|
||||||
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():
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Create action for regular nodes
|
# Create action for regular nodes
|
||||||
var action = _create_action_from_node(node_data)
|
var action = _create_action_from_node(scene, node_data)
|
||||||
if action:
|
if action:
|
||||||
cutscene_manager.add_action(action)
|
action_map[node_id] = action
|
||||||
|
|
||||||
|
# Second pass: Add actions with their dependencies
|
||||||
|
for node_id in action_map:
|
||||||
|
print("setting up", node_id)
|
||||||
|
var action = action_map[node_id]
|
||||||
|
|
||||||
# Add next nodes to queue
|
# Get dependencies (incoming connections)
|
||||||
var outgoing_connections = _get_outgoing_connections(current_node_id)
|
var deps = []
|
||||||
for conn in outgoing_connections:
|
var incoming_connections = _get_incoming_connections(node_id)
|
||||||
if not processed_nodes.has(conn["to_node"]):
|
|
||||||
node_queue.append(conn["to_node"])
|
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
|
# 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"]
|
var parameters = node_data["parameters"]
|
||||||
|
|
||||||
match node_data["type"]:
|
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
|
# In a real implementation, we would resolve the character path to an actual node
|
||||||
# For now, we'll create a placeholder
|
# 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)
|
var target_position = Vector2(target_x, target_y)
|
||||||
|
|
||||||
return MoveAction.new(character_node, target_position, speed)
|
return MoveAction.new(character_node, target_position, speed)
|
||||||
|
|||||||
50
addons/cutscene_editor/editor/CutsceneGraphEdit.gd
Normal file → Executable file
@@ -16,9 +16,6 @@ var node_counter: int = 0 # For generating unique node IDs
|
|||||||
var current_cutscene: CutsceneResource # The cutscene being edited
|
var current_cutscene: CutsceneResource # The cutscene being edited
|
||||||
|
|
||||||
# Preview properties
|
# Preview properties
|
||||||
var preview_manager: PreviewManager
|
|
||||||
var preview_panel: PreviewPanel
|
|
||||||
|
|
||||||
# Undo/Redo properties
|
# Undo/Redo properties
|
||||||
var undo_redo_manager: UndoRedoManager
|
var undo_redo_manager: UndoRedoManager
|
||||||
|
|
||||||
@@ -289,7 +286,7 @@ func _on_graph_node_deleted(node: BaseGraphNode) -> void:
|
|||||||
# Remove all connections to/from this node
|
# Remove all connections to/from this node
|
||||||
var connections = get_connection_list()
|
var connections = get_connection_list()
|
||||||
for connection in connections:
|
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"])
|
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
|
||||||
emit_signal("graph_changed")
|
emit_signal("graph_changed")
|
||||||
|
|
||||||
|
func get_graph_node_by_id(id: String):
|
||||||
|
return find_child(id)
|
||||||
|
|
||||||
# Load graph from cutscene resource
|
# Load graph from cutscene resource
|
||||||
func load_from_cutscene(cutscene: CutsceneResource) -> void:
|
func load_from_cutscene(cutscene: CutsceneResource) -> void:
|
||||||
# Clear existing graph
|
# Clear existing graph
|
||||||
@@ -343,14 +343,16 @@ func load_from_cutscene(cutscene: CutsceneResource) -> void:
|
|||||||
# Create nodes from cutscene data
|
# Create nodes from cutscene data
|
||||||
for node_data in cutscene.nodes:
|
for node_data in cutscene.nodes:
|
||||||
var node = add_node(node_data["type"], Vector2(node_data["position"]["x"], node_data["position"]["y"]))
|
var node = add_node(node_data["type"], Vector2(node_data["position"]["x"], node_data["position"]["y"]))
|
||||||
|
node.owner=self
|
||||||
if node:
|
if node:
|
||||||
node.node_id = node_data["id"]
|
node.name = node_data["id"]
|
||||||
# Set node parameters
|
# Set node parameters
|
||||||
for param_name in node_data["parameters"]:
|
for param_name in node_data["parameters"]:
|
||||||
node.set_parameter(param_name, node_data["parameters"][param_name])
|
node.set_parameter(param_name, node_data["parameters"][param_name])
|
||||||
|
|
||||||
# Create connections from cutscene data
|
# Create connections from cutscene data
|
||||||
for connection_data in cutscene.connections:
|
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"],
|
connect_node(connection_data["from_node"], connection_data["from_port"],
|
||||||
connection_data["to_node"], connection_data["to_port"])
|
connection_data["to_node"], connection_data["to_port"])
|
||||||
|
|
||||||
@@ -370,7 +372,7 @@ func save_to_cutscene() -> CutsceneResource:
|
|||||||
for child in get_children():
|
for child in get_children():
|
||||||
if child is BaseGraphNode:
|
if child is BaseGraphNode:
|
||||||
var node_data = {
|
var node_data = {
|
||||||
"id": child.node_id,
|
"id": str(child.name),
|
||||||
"type": child.node_type,
|
"type": child.node_type,
|
||||||
"position": {
|
"position": {
|
||||||
"x": child.position_offset.x,
|
"x": child.position_offset.x,
|
||||||
@@ -384,9 +386,9 @@ func save_to_cutscene() -> CutsceneResource:
|
|||||||
for connection in get_connection_list():
|
for connection in get_connection_list():
|
||||||
var connection_data = {
|
var connection_data = {
|
||||||
"id": _generate_unique_connection_id(),
|
"id": _generate_unique_connection_id(),
|
||||||
"from_node": connection["from_node"],
|
"from_node": str(connection["from_node"]),
|
||||||
"from_port": connection["from_port"],
|
"from_port": connection["from_port"],
|
||||||
"to_node": connection["to_node"],
|
"to_node": str(connection["to_node"]),
|
||||||
"to_port": connection["to_port"]
|
"to_port": connection["to_port"]
|
||||||
}
|
}
|
||||||
current_cutscene.connections.append(connection_data)
|
current_cutscene.connections.append(connection_data)
|
||||||
@@ -398,39 +400,7 @@ func _generate_unique_connection_id() -> String:
|
|||||||
return "conn_" + str(Time.get_ticks_msec())
|
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
|
# Set up undo/redo system
|
||||||
func _setup_undo_redo() -> void:
|
func _setup_undo_redo() -> void:
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
2
addons/cutscene_editor/editor/nodes/AnimationActionNode.gd
Normal file → Executable file
@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "animation"
|
node_type = "animation"
|
||||||
node_id = "animation_" + str(randi())
|
name = "animation_" + str(randi())
|
||||||
title = "Animation"
|
title = "Animation"
|
||||||
modulate = Color(0.8, 0.4, 0.8) # Purple
|
modulate = Color(0.8, 0.4, 0.8) # Purple
|
||||||
|
|
||||||
|
|||||||
0
addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn
Normal file → Executable file
2
addons/cutscene_editor/editor/nodes/BaseGraphNode.gd
Normal file → Executable file
@@ -20,7 +20,7 @@ enum NodeState {
|
|||||||
|
|
||||||
# Properties
|
# Properties
|
||||||
var node_type: String = "base"
|
var node_type: String = "base"
|
||||||
var node_id: String # Unique identifier for the node
|
|
||||||
var action_parameters: Dictionary = {} # Stores parameter values
|
var action_parameters: Dictionary = {} # Stores parameter values
|
||||||
var current_state: int = NodeState.IDLE
|
var current_state: int = NodeState.IDLE
|
||||||
var error_message: String = ""
|
var error_message: String = ""
|
||||||
|
|||||||
2
addons/cutscene_editor/editor/nodes/DialogueActionNode.gd
Normal file → Executable file
@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "dialogue"
|
node_type = "dialogue"
|
||||||
node_id = "dialogue_" + str(randi())
|
name = "dialogue_" + str(randi())
|
||||||
title = "Dialogue"
|
title = "Dialogue"
|
||||||
modulate = Color(1.0, 1.0, 0.5) # Yellow
|
modulate = Color(1.0, 1.0, 0.5) # Yellow
|
||||||
resizable=true
|
resizable=true
|
||||||
|
|||||||
0
addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn
Normal file → Executable file
2
addons/cutscene_editor/editor/nodes/EntryNode.gd
Normal file → Executable file
@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "entry"
|
node_type = "entry"
|
||||||
node_id = "entry_" + str(randi())
|
name = "entry_" + str(randi())
|
||||||
title = "Start"
|
title = "Start"
|
||||||
modulate = Color(0.5, 1.0, 0.5) # Light green
|
modulate = Color(0.5, 1.0, 0.5) # Light green
|
||||||
|
|
||||||
|
|||||||
14
addons/cutscene_editor/editor/nodes/EntryNode.tscn
Normal file → Executable 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"]
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/EntryNode.gd" id="1_entry"]
|
||||||
|
|
||||||
[node name="EntryNode" type="GraphNode"]
|
[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)
|
custom_minimum_size = Vector2(100, 0)
|
||||||
title = "Start"
|
title = "Start"
|
||||||
slot/0/left_enabled = false
|
slot/0/left_enabled = false
|
||||||
slot/0/left_type = 0
|
slot/0/left_type = 0
|
||||||
slot/0/left_color = Color(0, 0, 0, 0)
|
slot/0/left_color = Color(0, 0, 0, 0)
|
||||||
|
slot/0/left_icon = null
|
||||||
slot/0/right_enabled = true
|
slot/0/right_enabled = true
|
||||||
slot/0/right_type = 0
|
slot/0/right_type = 0
|
||||||
slot/0/right_color = Color(0, 0, 0, 1)
|
slot/0/right_color = Color(0, 0, 0, 1)
|
||||||
slot/0/right_icon = null
|
slot/0/right_icon = null
|
||||||
slot/0/draw_stylebox = true
|
slot/0/draw_stylebox = true
|
||||||
script = ExtResource("1_entry")
|
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
@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "exit"
|
node_type = "exit"
|
||||||
node_id = "exit_" + str(randi())
|
name = "exit_" + str(randi())
|
||||||
title = "End"
|
title = "End"
|
||||||
modulate = Color(1.0, 0.5, 0.5) # Light red
|
modulate = Color(1.0, 0.5, 0.5) # Light red
|
||||||
|
|
||||||
|
|||||||
12
addons/cutscene_editor/editor/nodes/ExitNode.tscn
Normal file → Executable file
@@ -1,14 +1,22 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://exitnodetscn"]
|
[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"]
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/ExitNode.gd" id="1_exit"]
|
||||||
|
|
||||||
[node name="ExitNode" type="GraphNode"]
|
[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)
|
custom_minimum_size = Vector2(100, 0)
|
||||||
title = "End"
|
title = "End"
|
||||||
slot/0/left_enabled = true
|
slot/0/left_enabled = true
|
||||||
slot/0/left_type = 0
|
slot/0/left_type = 0
|
||||||
slot/0/left_color = Color(0, 0, 0, 1)
|
slot/0/left_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/left_icon = null
|
||||||
slot/0/right_enabled = false
|
slot/0/right_enabled = false
|
||||||
slot/0/right_type = 0
|
slot/0/right_type = 0
|
||||||
slot/0/right_color = Color(0, 0, 0, 0)
|
slot/0/right_color = Color(0, 0, 0, 0)
|
||||||
|
slot/0/right_icon = null
|
||||||
slot/0/draw_stylebox = true
|
slot/0/draw_stylebox = true
|
||||||
script = ExtResource("1_exit")
|
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
@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "move"
|
node_type = "move"
|
||||||
node_id = "move_" + str(randi())
|
name = "move_" + str(randi())
|
||||||
title = "Move"
|
title = "Move"
|
||||||
modulate = Color(0.4, 0.6, 1.0) # Blue
|
modulate = Color(0.4, 0.6, 1.0) # Blue
|
||||||
|
|
||||||
@@ -22,6 +22,16 @@ func _ready() -> void:
|
|||||||
action_parameters["target_y"] = 0.0
|
action_parameters["target_y"] = 0.0
|
||||||
action_parameters["speed"] = 100.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:
|
func _on_character_changed(new_text: String) -> void:
|
||||||
set_parameter("character", new_text)
|
set_parameter("character", new_text)
|
||||||
|
|
||||||
|
|||||||
4
addons/cutscene_editor/editor/nodes/MoveActionNode.tscn
Normal file → Executable file
@@ -23,7 +23,7 @@ layout_mode = 2
|
|||||||
[node name="Character" type="Label" parent="VBoxContainer"]
|
[node name="Character" type="Label" parent="VBoxContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="TextEdit" type="LineEdit" parent="VBoxContainer"]
|
[node name="CharacterEDit" type="LineEdit" parent="VBoxContainer"]
|
||||||
custom_minimum_size = Vector2(0, 32.865)
|
custom_minimum_size = Vector2(0, 32.865)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "aoeu"
|
text = "aoeu"
|
||||||
@@ -49,7 +49,7 @@ text = "Speed"
|
|||||||
[node name="speed" type="LineEdit" parent="VBoxContainer"]
|
[node name="speed" type="LineEdit" parent="VBoxContainer"]
|
||||||
layout_mode = 2
|
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/x" to="." method="_on_target_x_changed"]
|
||||||
[connection signal="text_changed" from="VBoxContainer/HBoxContainer/y" to="." method="_on_target_y_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"]
|
[connection signal="text_change_rejected" from="VBoxContainer/speed" to="." method="_on_speed_text_change_rejected"]
|
||||||
|
|||||||
2
addons/cutscene_editor/editor/nodes/ParallelGroupNode.gd
Normal file → Executable file
@@ -14,7 +14,7 @@ var container_rect: PanelContainer # Visual container for child nodes
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "parallel"
|
node_type = "parallel"
|
||||||
node_id = "parallel_" + str(randi())
|
name = "parallel_" + str(randi())
|
||||||
title = "Parallel Group"
|
title = "Parallel Group"
|
||||||
modulate = Color(1.0, 0.6, 0.2) # Orange
|
modulate = Color(1.0, 0.6, 0.2) # Orange
|
||||||
|
|
||||||
|
|||||||
2
addons/cutscene_editor/editor/nodes/TurnActionNode.gd
Normal file → Executable file
@@ -6,7 +6,7 @@ extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
|||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
node_type = "turn"
|
node_type = "turn"
|
||||||
node_id = "turn_" + str(randi())
|
name = "turn_" + str(randi())
|
||||||
title = "Turn"
|
title = "Turn"
|
||||||
modulate = Color(0.5, 1.0, 0.5) # Green
|
modulate = Color(0.5, 1.0, 0.5) # Green
|
||||||
|
|
||||||
|
|||||||
0
addons/cutscene_editor/editor/nodes/TurnActionNode.tscn
Normal file → Executable file
0
addons/cutscene_editor/editor/nodes/WaitActionNode.gd
Normal file → Executable file
0
addons/cutscene_editor/editor/nodes/WaitActionNode.tscn
Normal file → Executable file
0
addons/cutscene_editor/editor/resources/CutsceneResource.gd
Normal file → Executable file
0
addons/cutscene_editor/icons/icon_animation.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_dialogue.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_entry.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_exit.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_move.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_parallel.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_turn.svg
Normal file → Executable 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
0
addons/cutscene_editor/icons/icon_wait.svg
Normal file → Executable 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
0
addons/cutscene_editor/plugin.cfg
Normal file → Executable file
0
addons/cutscene_editor/tests/test_cutscene_resource.gd
Normal file → Executable file
0
addons/cutscene_editor/tests/test_cutscene_resource.tscn
Normal file → Executable file
0
cutscene/Action.gd
Normal file → Executable file
196
cutscene/CutsceneManager.gd
Normal file → Executable file
@@ -1,14 +1,13 @@
|
|||||||
class_name CutsceneManager
|
class_name CutsceneManager
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
# Action queues
|
# Action dependency graph
|
||||||
var sequential_actions: Array = [] # Actions that run one after another
|
var actions: Dictionary = {} # Map of action IDs to action instances
|
||||||
var current_action: Action = null # The action currently being executed
|
var dependencies: Dictionary = {} # Map of action IDs to their dependency lists
|
||||||
var action_index: int = 0 # Index of the next sequential action
|
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)
|
||||||
# Parallel actions
|
var active_actions: Array = [] # Currently running actions
|
||||||
var parallel_groups: Array = [] # Groups of actions running simultaneously
|
var completed_actions: Array = [] # Actions that have completed
|
||||||
var active_parallel_groups: Array = [] # Currently running parallel action groups
|
|
||||||
|
|
||||||
# State management
|
# State management
|
||||||
enum State {
|
enum State {
|
||||||
@@ -39,8 +38,16 @@ func start() -> void:
|
|||||||
is_active = true
|
is_active = true
|
||||||
emit_signal("cutscene_started")
|
emit_signal("cutscene_started")
|
||||||
|
|
||||||
# Start first action
|
# Find actions with no dependencies to start with
|
||||||
_execute_next_action()
|
_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:
|
func pause() -> void:
|
||||||
# Pause the current cutscene
|
# Pause the current cutscene
|
||||||
@@ -56,67 +63,78 @@ func resume() -> void:
|
|||||||
|
|
||||||
func stop() -> void:
|
func stop() -> void:
|
||||||
# Stop the current cutscene and reset
|
# Stop the current cutscene and reset
|
||||||
if current_action != null:
|
# Stop all active actions
|
||||||
current_action.stop()
|
for action in active_actions:
|
||||||
current_action = null
|
if action.state == action.State.RUNNING:
|
||||||
|
action.stop()
|
||||||
|
|
||||||
# Stop all active parallel groups
|
active_actions.clear()
|
||||||
for group in active_parallel_groups:
|
|
||||||
for action in group["actions"]:
|
|
||||||
if action.state == action.State.RUNNING:
|
|
||||||
action.stop()
|
|
||||||
|
|
||||||
_reset()
|
_reset()
|
||||||
|
|
||||||
func add_action(action: Action) -> void:
|
func add_action(action_id: String, action: Action, deps: Array = []) -> void:
|
||||||
# Add a single action to the sequential queue
|
# Add an action with its dependencies
|
||||||
if state != State.IDLE:
|
if state != State.IDLE:
|
||||||
print("Warning: Cannot add actions while cutscene is running")
|
print("Warning: Cannot add actions while cutscene is running")
|
||||||
return
|
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
|
# Internal methods
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
# Main update loop
|
# Main update loop
|
||||||
if state != State.RUNNING:
|
if state != State.RUNNING:
|
||||||
return
|
return
|
||||||
|
# Find actions with no dependencies to start with
|
||||||
|
_find_ready_actions()
|
||||||
|
|
||||||
# Update current sequential action
|
# Start all ready actions
|
||||||
if current_action != null and current_action.state == current_action.State.RUNNING:
|
for action_id in ready_actions:
|
||||||
current_action.update(delta)
|
_execute_action(action_id)
|
||||||
|
|
||||||
# Update active parallel groups
|
# Update all active actions
|
||||||
for group in active_parallel_groups:
|
for action in active_actions:
|
||||||
for action in group["actions"]:
|
if action.state == action.State.RUNNING:
|
||||||
if action.state == action.State.RUNNING:
|
action.update(delta)
|
||||||
action.update(delta)
|
|
||||||
|
|
||||||
func _execute_next_action() -> void:
|
func _find_ready_actions() -> void:
|
||||||
# Start executing the next sequential action
|
# Find actions that are ready to execute (all dependencies met)
|
||||||
if action_index >= sequential_actions.size():
|
ready_actions.clear()
|
||||||
# No more actions, cutscene complete
|
|
||||||
_on_cutscene_completed()
|
|
||||||
return
|
|
||||||
|
|
||||||
var action_item = sequential_actions[action_index]
|
for action_id in actions:
|
||||||
action_index += 1
|
# Skip if already completed or active
|
||||||
print(action_item)
|
if completed_actions.has(action_id) or active_actions.has(actions[action_id]):
|
||||||
# Check if this is a parallel group or single action
|
continue
|
||||||
if typeof(action_item) == TYPE_DICTIONARY and action_item.has("actions"):
|
|
||||||
# This is a parallel group
|
# Check if all dependencies are met
|
||||||
_execute_parallel_group(action_item)
|
var all_deps_met = true
|
||||||
else:
|
for dep_id in dependencies[action_id]:
|
||||||
# This is a single action
|
if not completed_actions.has(dep_id):
|
||||||
_execute_single_action(action_item)
|
all_deps_met = false
|
||||||
|
break
|
||||||
|
|
||||||
func _execute_single_action(action: Action) -> void:
|
if all_deps_met:
|
||||||
|
ready_actions.append(action_id)
|
||||||
|
|
||||||
|
func _execute_action(action_id: String) -> void:
|
||||||
# Execute a single action
|
# 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
|
# Connect to action signals
|
||||||
if not action.is_connected("completed", _on_action_completed):
|
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):
|
if not action.is_connected("failed", _on_action_failed):
|
||||||
action.connect("failed", _on_action_failed.bind(action))
|
action.connect("failed", _on_action_failed.bind(action))
|
||||||
if not action.is_connected("started", _on_action_started):
|
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)
|
emit_signal("action_started", action)
|
||||||
action.start()
|
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:
|
func _on_action_started(action: Action) -> void:
|
||||||
# Handle action started
|
# Handle action started
|
||||||
emit_signal("action_started", action)
|
emit_signal("action_started", action)
|
||||||
|
|
||||||
func _on_action_completed(action: Action) -> void:
|
func _on_action_completed(action_id: String) -> void:
|
||||||
# Handle action completion
|
# Handle action completion
|
||||||
if action == current_action:
|
var action = actions[action_id]
|
||||||
current_action = null
|
active_actions.erase(action)
|
||||||
emit_signal("action_completed", action)
|
completed_actions.append(action_id)
|
||||||
# Move to next action
|
emit_signal("action_completed", 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:
|
func _on_action_failed(action: Action, error_message: String) -> void:
|
||||||
# Handle action failure
|
# Handle action failure
|
||||||
if action == current_action:
|
active_actions.erase(action)
|
||||||
current_action = null
|
|
||||||
|
|
||||||
emit_signal("action_failed", action, error_message)
|
emit_signal("action_failed", action, error_message)
|
||||||
print("Action failed: %s - %s" % [action.name, error_message])
|
print("Action failed: %s - %s" % [action.name, error_message])
|
||||||
# Stop the cutscene
|
# Stop the cutscene
|
||||||
stop()
|
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:
|
func _on_cutscene_completed() -> void:
|
||||||
# Handle cutscene completion
|
# Handle cutscene completion
|
||||||
state = State.IDLE
|
state = State.IDLE
|
||||||
@@ -200,10 +183,11 @@ func _on_cutscene_completed() -> void:
|
|||||||
|
|
||||||
func _reset() -> void:
|
func _reset() -> void:
|
||||||
# Reset the manager to initial state
|
# Reset the manager to initial state
|
||||||
sequential_actions.clear()
|
actions.clear()
|
||||||
parallel_groups.clear()
|
dependencies.clear()
|
||||||
active_parallel_groups.clear()
|
dependents.clear()
|
||||||
current_action = null
|
ready_actions.clear()
|
||||||
action_index = 0
|
active_actions.clear()
|
||||||
|
completed_actions.clear()
|
||||||
state = State.IDLE
|
state = State.IDLE
|
||||||
is_active = false
|
is_active = false
|
||||||
|
|||||||
0
cutscene/README.md
Normal file → Executable file
0
cutscene/actions/AnimationAction.gd
Normal file → Executable file
0
cutscene/actions/DialogueAction.gd
Normal file → Executable file
1
cutscene/actions/MoveAction.gd
Normal file → Executable file
@@ -30,7 +30,6 @@ func start() -> void:
|
|||||||
self._set_running()
|
self._set_running()
|
||||||
|
|
||||||
func update(delta: float) -> void:
|
func update(delta: float) -> void:
|
||||||
print ("updating")
|
|
||||||
if state != State.RUNNING:
|
if state != State.RUNNING:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
0
cutscene/actions/TurnAction.gd
Normal file → Executable file
0
cutscene/actions/WaitAction.gd
Normal file → Executable file
2
example_cutscene.tscn
Normal file → Executable 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"]
|
[sub_resource type="GDScript" id="GDScript_e7tbc"]
|
||||||
script/source = "extends Node2D
|
script/source = "extends Node2D
|
||||||
|
|||||||
34
hello.tres
@@ -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
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 994 B |
0
icon.svg.import
Normal file → Executable file
0
plans/cutscene_data_structure.md
Normal file → Executable file
0
plans/cutscene_documentation_plan.md
Normal file → Executable file
0
plans/cutscene_generator_changes.md
Normal file → Executable file
0
plans/cutscene_graph_edit_changes.md
Normal file → Executable file
0
plans/cutscene_resource_analysis.md
Normal file → Executable file
0
plans/cutscene_resource_implementation.md
Normal file → Executable file
0
plans/cutscene_resource_implementation_summary.md
Normal file → Executable file
0
plans/cutscene_test_plan.md
Normal file → Executable file
2
project.godot
Normal file → Executable file
@@ -12,7 +12,7 @@ config_version=5
|
|||||||
|
|
||||||
config/name="adventure-ai"
|
config/name="adventure-ai"
|
||||||
run/main_scene="res://main.tscn"
|
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"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|||||||
18
tes2265.tmp
Executable 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -37,7 +37,7 @@ func setup_cutscene() -> void:
|
|||||||
|
|
||||||
# Generate actions from the resource
|
# Generate actions from the resource
|
||||||
var generator = CutsceneGenerator.new()
|
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 the cutscene manager to the scene
|
||||||
add_child(cutscene_manager)
|
add_child(cutscene_manager)
|
||||||
@@ -77,7 +77,7 @@ func create_test_cutscene_resource() -> CutsceneResource:
|
|||||||
"type": "move",
|
"type": "move",
|
||||||
"position": {"x": 250, "y": 150},
|
"position": {"x": 250, "y": 150},
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"character": "character2",
|
"character": "Character2",
|
||||||
"target_x": 912,
|
"target_x": 912,
|
||||||
"target_y": 235,
|
"target_y": 235,
|
||||||
"speed": 100.0
|
"speed": 100.0
|
||||||
@@ -223,10 +223,10 @@ func _on_cutscene_completed() -> void:
|
|||||||
print("Character2: %s" % character2.position)
|
print("Character2: %s" % character2.position)
|
||||||
|
|
||||||
func _on_action_started(action: Action) -> void:
|
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:
|
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
|
# Clean up when the node is removed
|
||||||
func _exit_tree() -> void:
|
func _exit_tree() -> void:
|
||||||
|
|||||||