improvement
This commit is contained in:
@@ -57,31 +57,25 @@ func add_node(node_type: String, position: Vector2) -> BaseGraphNode:
|
|||||||
|
|
||||||
match node_type:
|
match node_type:
|
||||||
"entry":
|
"entry":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/EntryNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/EntryNode.tscn").instantiate()
|
||||||
"exit":
|
"exit":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/ExitNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/ExitNode.tscn").instantiate()
|
||||||
"move":
|
"move":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/MoveActionNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/MoveActionNode.tscn").instantiate()
|
||||||
"turn":
|
"turn":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/TurnActionNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/TurnActionNode.tscn").instantiate()
|
||||||
"dialogue":
|
"dialogue":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/DialogueActionNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn").instantiate()
|
||||||
"animation":
|
"animation":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/AnimationActionNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn").instantiate()
|
||||||
"wait":
|
"wait":
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/WaitActionNode.gd").new()
|
new_node = preload("res://addons/cutscene_editor/editor/nodes/WaitActionNode.tscn").instantiate()
|
||||||
"parallel":
|
|
||||||
new_node = preload("res://addons/cutscene_editor/editor/nodes/ParallelGroupNode.gd").new()
|
|
||||||
_:
|
_:
|
||||||
return null
|
return null
|
||||||
|
|
||||||
# Set node position
|
# Set node position
|
||||||
new_node.position_offset = position
|
new_node.position_offset = position
|
||||||
|
|
||||||
# Special handling for parallel groups
|
|
||||||
if new_node is ParallelGroupNode:
|
|
||||||
# Set a larger initial size for parallel groups
|
|
||||||
new_node.custom_minimum_size = Vector2(200, 150)
|
|
||||||
|
|
||||||
# Add to GraphEdit
|
# Add to GraphEdit
|
||||||
add_child(new_node)
|
add_child(new_node)
|
||||||
@@ -105,21 +99,6 @@ func _on_connection_request(from_node: String, from_port: int, to_node: String,
|
|||||||
var from_node_instance = get_node_or_null(from_node)
|
var from_node_instance = get_node_or_null(from_node)
|
||||||
var to_node_instance = get_node_or_null(to_node)
|
var to_node_instance = get_node_or_null(to_node)
|
||||||
|
|
||||||
# Special handling for parallel groups
|
|
||||||
if to_node_instance is ParallelGroupNode:
|
|
||||||
# Connecting to a parallel group
|
|
||||||
if _is_valid_parallel_connection(from_node_instance, from_port, to_node_instance, to_port):
|
|
||||||
# Add child node to parallel group
|
|
||||||
if to_node_instance.can_add_child_node(from_node_instance):
|
|
||||||
to_node_instance.add_child_node(from_node_instance)
|
|
||||||
|
|
||||||
# Create a logical connection (not visual)
|
|
||||||
_create_logical_parallel_connection(from_node, from_port, to_node, to_port)
|
|
||||||
|
|
||||||
# Emit signal
|
|
||||||
emit_signal("connection_created", from_node, from_port, to_node, to_port)
|
|
||||||
emit_signal("graph_changed")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create the connection
|
# Create the connection
|
||||||
connect_node(from_node, from_port, to_node, to_port)
|
connect_node(from_node, from_port, to_node, to_port)
|
||||||
@@ -137,19 +116,6 @@ func _on_disconnection_request(from_node: String, from_port: int, to_node: Strin
|
|||||||
var from_node_instance = get_node_or_null(from_node)
|
var from_node_instance = get_node_or_null(from_node)
|
||||||
var to_node_instance = get_node_or_null(to_node)
|
var to_node_instance = get_node_or_null(to_node)
|
||||||
|
|
||||||
# Special handling for parallel groups
|
|
||||||
if to_node_instance is ParallelGroupNode:
|
|
||||||
# Remove child node from parallel group
|
|
||||||
if from_node_instance in to_node_instance.child_nodes:
|
|
||||||
to_node_instance.remove_child_node(from_node_instance)
|
|
||||||
|
|
||||||
# Remove logical connection
|
|
||||||
_remove_logical_parallel_connection(from_node, from_port, to_node, to_port)
|
|
||||||
|
|
||||||
# Emit signal
|
|
||||||
emit_signal("connection_removed", from_node, from_port, to_node, to_port)
|
|
||||||
emit_signal("graph_changed")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Remove the connection
|
# Remove the connection
|
||||||
disconnect_node(from_node, from_port, to_node, to_port)
|
disconnect_node(from_node, from_port, to_node, to_port)
|
||||||
@@ -187,12 +153,6 @@ func _is_connection_valid(from_node_name: String, from_port: int, to_node_name:
|
|||||||
"exit":
|
"exit":
|
||||||
# Exit cannot have outgoing connections
|
# Exit cannot have outgoing connections
|
||||||
return false
|
return false
|
||||||
"parallel":
|
|
||||||
# Parallel group output can connect to any node except entry/parallel
|
|
||||||
if from_port == from_node.input_connections: # Output port
|
|
||||||
return to_node.node_type != "entry" and to_node.node_type != "parallel"
|
|
||||||
else: # Input port
|
|
||||||
return to_node.node_type != "exit" and to_node.node_type != "parallel"
|
|
||||||
_:
|
_:
|
||||||
# Other nodes can connect to any node except entry
|
# Other nodes can connect to any node except entry
|
||||||
return to_node.node_type != "entry"
|
return to_node.node_type != "entry"
|
||||||
@@ -231,24 +191,6 @@ func _dfs_cycle_check(current_node_name: String, target_node_name: String, visit
|
|||||||
elif recursion_stack.has(next_node_name):
|
elif recursion_stack.has(next_node_name):
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Check parallel connections
|
|
||||||
if has_meta("logical_connections"):
|
|
||||||
var logical_connections = get_meta("logical_connections")
|
|
||||||
for connection in logical_connections:
|
|
||||||
if connection["from_node"] == current_node_name:
|
|
||||||
var next_node_name = connection["to_node"]
|
|
||||||
|
|
||||||
# If we reached the target node, we found a cycle
|
|
||||||
if next_node_name == target_node_name:
|
|
||||||
return true
|
|
||||||
|
|
||||||
# If next node not visited, recursively check
|
|
||||||
if not visited.has(next_node_name):
|
|
||||||
if _dfs_cycle_check(next_node_name, target_node_name, visited, recursion_stack):
|
|
||||||
return true
|
|
||||||
# If next node is in recursion stack, we found a cycle
|
|
||||||
elif recursion_stack.has(next_node_name):
|
|
||||||
return true
|
|
||||||
|
|
||||||
# Remove from recursion stack
|
# Remove from recursion stack
|
||||||
recursion_stack[current_node_name] = false
|
recursion_stack[current_node_name] = false
|
||||||
@@ -274,7 +216,6 @@ func _on_popup_request(position: Vector2) -> void:
|
|||||||
menu.add_item("Add Dialogue Action", 4)
|
menu.add_item("Add Dialogue Action", 4)
|
||||||
menu.add_item("Add Animation Action", 5)
|
menu.add_item("Add Animation Action", 5)
|
||||||
menu.add_item("Add Wait Action", 6)
|
menu.add_item("Add Wait Action", 6)
|
||||||
menu.add_item("Add Parallel Group", 7)
|
|
||||||
|
|
||||||
# Connect menu signals
|
# Connect menu signals
|
||||||
menu.connect("id_pressed", _on_context_menu_selected.bind(position))
|
menu.connect("id_pressed", _on_context_menu_selected.bind(position))
|
||||||
@@ -303,8 +244,6 @@ func _on_context_menu_selected(id: int, position: Vector2) -> void:
|
|||||||
node_type = "animation"
|
node_type = "animation"
|
||||||
6:
|
6:
|
||||||
node_type = "wait"
|
node_type = "wait"
|
||||||
7:
|
|
||||||
node_type = "parallel"
|
|
||||||
_:
|
_:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -346,22 +285,6 @@ func _on_graph_node_selected(node: BaseGraphNode) -> void:
|
|||||||
|
|
||||||
# Handle graph node deletion
|
# Handle graph node deletion
|
||||||
func _on_graph_node_deleted(node: BaseGraphNode) -> void:
|
func _on_graph_node_deleted(node: BaseGraphNode) -> void:
|
||||||
# Special handling for parallel groups
|
|
||||||
if node is ParallelGroupNode:
|
|
||||||
# Remove all child nodes first
|
|
||||||
for child_node in node.child_nodes:
|
|
||||||
# Remove child from scene tree
|
|
||||||
if child_node.get_parent():
|
|
||||||
child_node.get_parent().remove_child(child_node)
|
|
||||||
|
|
||||||
# Add child back to main graph
|
|
||||||
add_child(child_node)
|
|
||||||
|
|
||||||
# Update child position to be near the parallel group
|
|
||||||
child_node.position_offset = node.position_offset + Vector2(50, 50)
|
|
||||||
|
|
||||||
# Clear child nodes array
|
|
||||||
node.child_nodes.clear()
|
|
||||||
|
|
||||||
# Remove all connections to/from this node
|
# Remove all connections to/from this node
|
||||||
var connections = get_connection_list()
|
var connections = get_connection_list()
|
||||||
@@ -369,16 +292,6 @@ func _on_graph_node_deleted(node: BaseGraphNode) -> void:
|
|||||||
if connection["from_node"] == node.name or connection["to_node"] == node.name:
|
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"])
|
||||||
|
|
||||||
# Remove logical connections for parallel groups
|
|
||||||
if has_meta("logical_connections"):
|
|
||||||
var logical_connections = get_meta("logical_connections")
|
|
||||||
var i = 0
|
|
||||||
while i < logical_connections.size():
|
|
||||||
var conn = logical_connections[i]
|
|
||||||
if conn["from_node"] == node.name or conn["to_node"] == node.name:
|
|
||||||
logical_connections.remove_at(i)
|
|
||||||
else:
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# Remove node from GraphEdit
|
# Remove node from GraphEdit
|
||||||
remove_child(node)
|
remove_child(node)
|
||||||
@@ -477,65 +390,6 @@ func save_to_cutscene() -> CutsceneResource:
|
|||||||
|
|
||||||
return current_cutscene
|
return current_cutscene
|
||||||
|
|
||||||
# Special handling for parallel groups
|
|
||||||
func _is_valid_parallel_connection(from_node: BaseGraphNode, from_port: int, to_node: ParallelGroupNode, to_port: int) -> bool:
|
|
||||||
# Can only connect to input ports of parallel groups
|
|
||||||
if to_port >= to_node.input_connections:
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Can't connect parallel group to itself
|
|
||||||
if from_node == to_node:
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Can't connect entry or exit nodes to parallel groups
|
|
||||||
if from_node.node_type == "entry" or from_node.node_type == "exit":
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Can't connect parallel groups to parallel groups
|
|
||||||
if from_node.node_type == "parallel":
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
# Create a logical connection for parallel groups (not visually represented)
|
|
||||||
func _create_logical_parallel_connection(from_node: String, from_port: int, to_node: String, to_port: int) -> void:
|
|
||||||
# Store the logical connection in our data structure
|
|
||||||
# This connection won't be visually represented but will be used for generation
|
|
||||||
var logical_connection = {
|
|
||||||
"from_node": from_node,
|
|
||||||
"from_port": from_port,
|
|
||||||
"to_node": to_node,
|
|
||||||
"to_port": to_port,
|
|
||||||
"is_parallel": true
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add to a separate list of logical connections
|
|
||||||
if not has_meta("logical_connections"):
|
|
||||||
set_meta("logical_connections", [])
|
|
||||||
|
|
||||||
var logical_connections = get_meta("logical_connections")
|
|
||||||
logical_connections.append(logical_connection)
|
|
||||||
|
|
||||||
# Remove a logical connection for parallel groups
|
|
||||||
func _remove_logical_parallel_connection(from_node: String, from_port: int, to_node: String, to_port: int) -> void:
|
|
||||||
if not has_meta("logical_connections"):
|
|
||||||
return
|
|
||||||
|
|
||||||
var logical_connections = get_meta("logical_connections")
|
|
||||||
var i = 0
|
|
||||||
while i < logical_connections.size():
|
|
||||||
var conn = logical_connections[i]
|
|
||||||
if (conn["from_node"] == from_node and conn["from_port"] == from_port and
|
|
||||||
conn["to_node"] == to_node and conn["to_port"] == to_port):
|
|
||||||
logical_connections.remove_at(i)
|
|
||||||
return
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# Get all logical connections
|
|
||||||
func get_logical_connections() -> Array:
|
|
||||||
if has_meta("logical_connections"):
|
|
||||||
return get_meta("logical_connections")
|
|
||||||
return []
|
|
||||||
|
|
||||||
# Set up preview system
|
# Set up preview system
|
||||||
func setup_preview() -> void:
|
func setup_preview() -> void:
|
||||||
|
|||||||
@@ -21,37 +21,6 @@ func _ready() -> void:
|
|||||||
action_parameters["animation_name"] = ""
|
action_parameters["animation_name"] = ""
|
||||||
action_parameters["loop"] = false
|
action_parameters["loop"] = false
|
||||||
|
|
||||||
func _setup_parameter_fields() -> void:
|
|
||||||
# Character field
|
|
||||||
var char_label = Label.new()
|
|
||||||
char_label.text = "Character:"
|
|
||||||
add_child(char_label)
|
|
||||||
|
|
||||||
var char_field = LineEdit.new()
|
|
||||||
char_field.text = action_parameters["character"]
|
|
||||||
char_field.connect("text_changed", _on_character_changed)
|
|
||||||
add_child(char_field)
|
|
||||||
|
|
||||||
# Animation name field
|
|
||||||
var anim_label = Label.new()
|
|
||||||
anim_label.text = "Animation:"
|
|
||||||
add_child(anim_label)
|
|
||||||
|
|
||||||
var anim_field = LineEdit.new()
|
|
||||||
anim_field.text = action_parameters["animation_name"]
|
|
||||||
anim_field.connect("text_changed", _on_animation_changed)
|
|
||||||
add_child(anim_field)
|
|
||||||
|
|
||||||
# Loop checkbox
|
|
||||||
var loop_label = Label.new()
|
|
||||||
loop_label.text = "Loop:"
|
|
||||||
add_child(loop_label)
|
|
||||||
|
|
||||||
var loop_checkbox = CheckBox.new()
|
|
||||||
loop_checkbox.button_pressed = action_parameters["loop"]
|
|
||||||
loop_checkbox.connect("toggled", _on_loop_toggled)
|
|
||||||
add_child(loop_checkbox)
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|||||||
36
addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn
Normal file
36
addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://animationactionnodetscn"]
|
||||||
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/AnimationActionNode.gd" id="1_animation"]
|
||||||
|
[node name="AnimationActionNode" type="GraphNode"]
|
||||||
|
modulate = Color(0.8, 0.4, 0.8, 1)
|
||||||
|
custom_minimum_size = Vector2(150, 0)
|
||||||
|
title = "Animation"
|
||||||
|
slot/0/left_enabled = true
|
||||||
|
slot/0/left_type = 0
|
||||||
|
slot/0/left_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/right_enabled = true
|
||||||
|
slot/0/right_type = 0
|
||||||
|
slot/0/right_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/draw_stylebox = true
|
||||||
|
script = ExtResource("1_animation")
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
[node name="Character" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Character"
|
||||||
|
[node name="character" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Character name"
|
||||||
|
[node name="Animation" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Animation"
|
||||||
|
[node name="animation_name" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Animation name"
|
||||||
|
[node name="Loop" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Loop"
|
||||||
|
[node name="loop" type="CheckBox" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/character" to="." method="_on_character_changed"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/animation_name" to="." method="_on_animation_changed"]
|
||||||
|
[connection signal="toggled" from="VBoxContainer/loop" to="." method="_on_loop_toggled"]
|
||||||
@@ -21,47 +21,11 @@ func _ready() -> void:
|
|||||||
action_parameters["text"] = ""
|
action_parameters["text"] = ""
|
||||||
action_parameters["duration"] = 0.0
|
action_parameters["duration"] = 0.0
|
||||||
|
|
||||||
func _setup_parameter_fields() -> void:
|
|
||||||
# Character field
|
|
||||||
var x = VBoxContainer.new()
|
|
||||||
add_child(x)
|
|
||||||
var char_label = Label.new()
|
|
||||||
char_label.text = "Character:"
|
|
||||||
char_label.hide()
|
|
||||||
x.add_child(char_label)
|
|
||||||
|
|
||||||
var char_field = LineEdit.new()
|
|
||||||
char_field.text = action_parameters["character"]
|
|
||||||
char_field.connect("text_changed", _on_character_changed)
|
|
||||||
x.add_child(char_field)
|
|
||||||
|
|
||||||
# Text field
|
|
||||||
var text_label = Label.new()
|
|
||||||
text_label.text = "Text:"
|
|
||||||
x.add_child(text_label)
|
|
||||||
|
|
||||||
var text_field = TextEdit.new()
|
|
||||||
text_field.text = action_parameters["text"]
|
|
||||||
text_field.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
||||||
text_field.connect("text_changed", _on_text_changed)
|
|
||||||
x.add_child(text_field)
|
|
||||||
|
|
||||||
# Duration field
|
|
||||||
var duration_label = Label.new()
|
|
||||||
duration_label.text = "Duration:"
|
|
||||||
x.add_child(duration_label)
|
|
||||||
|
|
||||||
var duration_field = LineEdit.new()
|
|
||||||
duration_field.text = str(action_parameters["duration"])
|
|
||||||
duration_field.connect("text_changed", _on_duration_changed)
|
|
||||||
x.add_child(duration_field)
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
func _on_text_changed() -> void:
|
func _on_text_changed(new_text: String) -> void:
|
||||||
var text_edit = get_child(get_child_count() - 2) # TextEdit is second to last child
|
set_parameter("text", new_text)
|
||||||
set_parameter("text", text_edit.text)
|
|
||||||
|
|
||||||
func _on_duration_changed(new_text: String) -> void:
|
func _on_duration_changed(new_text: String) -> void:
|
||||||
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
||||||
|
|||||||
38
addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn
Normal file
38
addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dialogueactionnodetscn"]
|
||||||
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/DialogueActionNode.gd" id="1_dialogue"]
|
||||||
|
[node name="DialogueActionNode" type="GraphNode"]
|
||||||
|
modulate = Color(1.0, 1.0, 0.5, 1)
|
||||||
|
custom_minimum_size = Vector2(200, 100)
|
||||||
|
title = "Dialogue"
|
||||||
|
resizable = true
|
||||||
|
slot/0/left_enabled = true
|
||||||
|
slot/0/left_type = 0
|
||||||
|
slot/0/left_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/right_enabled = true
|
||||||
|
slot/0/right_type = 0
|
||||||
|
slot/0/right_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/draw_stylebox = true
|
||||||
|
script = ExtResource("1_dialogue")
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
[node name="Character" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Character"
|
||||||
|
[node name="character" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Character name"
|
||||||
|
[node name="Text" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Text"
|
||||||
|
[node name="text" type="TextEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
[node name="Duration" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Duration"
|
||||||
|
[node name="duration" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Duration in seconds"
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/character" to="." method="_on_character_changed"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/text" to="." method="_on_text_changed"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/duration" to="." method="_on_duration_changed"]
|
||||||
15
addons/cutscene_editor/editor/nodes/EntryNode.tscn
Normal file
15
addons/cutscene_editor/editor/nodes/EntryNode.tscn
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://entrynodetscn"]
|
||||||
|
[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)
|
||||||
|
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/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")
|
||||||
14
addons/cutscene_editor/editor/nodes/ExitNode.tscn
Normal file
14
addons/cutscene_editor/editor/nodes/ExitNode.tscn
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[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)
|
||||||
|
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/right_enabled = false
|
||||||
|
slot/0/right_type = 0
|
||||||
|
slot/0/right_color = Color(0, 0, 0, 0)
|
||||||
|
slot/0/draw_stylebox = true
|
||||||
|
script = ExtResource("1_exit")
|
||||||
@@ -22,56 +22,6 @@ 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 _setup_parameter_fields() -> void:
|
|
||||||
# Character field
|
|
||||||
var char_label = Label.new()
|
|
||||||
char_label.text = "Character:"
|
|
||||||
add_child(char_label)
|
|
||||||
|
|
||||||
var char_field = LineEdit.new()
|
|
||||||
char_field.text = action_parameters["character"]
|
|
||||||
char_field.connect("text_changed", _on_character_changed)
|
|
||||||
add_child(char_field)
|
|
||||||
|
|
||||||
# Target position fields
|
|
||||||
var pos_label = Label.new()
|
|
||||||
pos_label.text = "Target Position:"
|
|
||||||
add_child(pos_label)
|
|
||||||
|
|
||||||
var pos_container = HBoxContainer.new()
|
|
||||||
|
|
||||||
var x_label = Label.new()
|
|
||||||
x_label.text = "X:"
|
|
||||||
pos_container.add_child(x_label)
|
|
||||||
|
|
||||||
var x_field = LineEdit.new()
|
|
||||||
x_field.text = str(action_parameters["target_x"])
|
|
||||||
x_field.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
||||||
x_field.connect("text_changed", _on_target_x_changed)
|
|
||||||
pos_container.add_child(x_field)
|
|
||||||
|
|
||||||
var y_label = Label.new()
|
|
||||||
y_label.text = "Y:"
|
|
||||||
pos_container.add_child(y_label)
|
|
||||||
|
|
||||||
var y_field = LineEdit.new()
|
|
||||||
y_field.text = str(action_parameters["target_y"])
|
|
||||||
y_field.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
||||||
y_field.connect("text_changed", _on_target_y_changed)
|
|
||||||
pos_container.add_child(y_field)
|
|
||||||
|
|
||||||
add_child(pos_container)
|
|
||||||
|
|
||||||
# Speed field
|
|
||||||
var speed_label = Label.new()
|
|
||||||
speed_label.text = "Speed:"
|
|
||||||
add_child(speed_label)
|
|
||||||
|
|
||||||
var speed_field = LineEdit.new()
|
|
||||||
speed_field.text = str(action_parameters["speed"])
|
|
||||||
speed_field.connect("text_changed", _on_speed_changed)
|
|
||||||
add_child(speed_field)
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@@ -80,9 +30,12 @@ func _on_target_x_changed(new_text: String) -> void:
|
|||||||
set_parameter("target_x", value)
|
set_parameter("target_x", value)
|
||||||
|
|
||||||
func _on_target_y_changed(new_text: String) -> void:
|
func _on_target_y_changed(new_text: String) -> void:
|
||||||
|
print("toarget y")
|
||||||
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
||||||
set_parameter("target_y", value)
|
set_parameter("target_y", value)
|
||||||
|
|
||||||
func _on_speed_changed(new_text: String) -> void:
|
func _on_speed_changed(new_text: String) -> void:
|
||||||
|
|
||||||
|
print("speed")
|
||||||
var value = float(new_text) if new_text.is_valid_float() else 100.0
|
var value = float(new_text) if new_text.is_valid_float() else 100.0
|
||||||
set_parameter("speed", value)
|
set_parameter("speed", value)
|
||||||
|
|||||||
56
addons/cutscene_editor/editor/nodes/MoveActionNode.tscn
Normal file
56
addons/cutscene_editor/editor/nodes/MoveActionNode.tscn
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://y74lqsx8bpxn"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/MoveActionNode.gd" id="1_5aood"]
|
||||||
|
|
||||||
|
[node name="MoveActionNode" type="GraphNode"]
|
||||||
|
modulate = Color(0.4, 0.6, 1, 1)
|
||||||
|
custom_minimum_size = Vector2(150, 0)
|
||||||
|
title = "Move"
|
||||||
|
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 = 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_5aood")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Character" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="TextEdit" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
custom_minimum_size = Vector2(0, 32.865)
|
||||||
|
layout_mode = 2
|
||||||
|
text = "aoeu"
|
||||||
|
placeholder_text = "aoeu"
|
||||||
|
|
||||||
|
[node name="Location" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Location"
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="x" type="LineEdit" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="y" type="LineEdit" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Speed" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
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/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"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/speed" to="." method="_on_speed_changed"]
|
||||||
@@ -21,37 +21,6 @@ func _ready() -> void:
|
|||||||
action_parameters["target"] = ""
|
action_parameters["target"] = ""
|
||||||
action_parameters["turn_speed"] = 2.0
|
action_parameters["turn_speed"] = 2.0
|
||||||
|
|
||||||
func _setup_parameter_fields() -> void:
|
|
||||||
# Character field
|
|
||||||
var char_label = Label.new()
|
|
||||||
char_label.text = "Character:"
|
|
||||||
add_child(char_label)
|
|
||||||
|
|
||||||
var char_field = LineEdit.new()
|
|
||||||
char_field.text = action_parameters["character"]
|
|
||||||
char_field.connect("text_changed", _on_character_changed)
|
|
||||||
add_child(char_field)
|
|
||||||
|
|
||||||
# Target field
|
|
||||||
var target_label = Label.new()
|
|
||||||
target_label.text = "Target:"
|
|
||||||
add_child(target_label)
|
|
||||||
|
|
||||||
var target_field = LineEdit.new()
|
|
||||||
target_field.text = action_parameters["target"]
|
|
||||||
target_field.connect("text_changed", _on_target_changed)
|
|
||||||
add_child(target_field)
|
|
||||||
|
|
||||||
# Turn speed field
|
|
||||||
var speed_label = Label.new()
|
|
||||||
speed_label.text = "Turn Speed:"
|
|
||||||
add_child(speed_label)
|
|
||||||
|
|
||||||
var speed_field = LineEdit.new()
|
|
||||||
speed_field.text = str(action_parameters["turn_speed"])
|
|
||||||
speed_field.connect("text_changed", _on_turn_speed_changed)
|
|
||||||
add_child(speed_field)
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|||||||
37
addons/cutscene_editor/editor/nodes/TurnActionNode.tscn
Normal file
37
addons/cutscene_editor/editor/nodes/TurnActionNode.tscn
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://turnactionnodetscn"]
|
||||||
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/TurnActionNode.gd" id="1_turn"]
|
||||||
|
[node name="TurnActionNode" type="GraphNode"]
|
||||||
|
modulate = Color(0.5, 1.0, 0.5, 1)
|
||||||
|
custom_minimum_size = Vector2(150, 0)
|
||||||
|
title = "Turn"
|
||||||
|
slot/0/left_enabled = true
|
||||||
|
slot/0/left_type = 0
|
||||||
|
slot/0/left_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/right_enabled = true
|
||||||
|
slot/0/right_type = 0
|
||||||
|
slot/0/right_color = Color(0, 0, 0, 1)
|
||||||
|
slot/0/draw_stylebox = true
|
||||||
|
script = ExtResource("1_turn")
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
[node name="Character" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Character"
|
||||||
|
[node name="character" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Character name"
|
||||||
|
[node name="Target" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Target"
|
||||||
|
[node name="target" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Target name"
|
||||||
|
[node name="TurnSpeed" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Turn Speed"
|
||||||
|
[node name="turn_speed" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
placeholder_text = "Turn speed"
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/character" to="." method="_on_character_changed"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/target" to="." method="_on_target_changed"]
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/turn_speed" to="." method="_on_turn_speed_changed"]
|
||||||
@@ -19,17 +19,6 @@ func _ready() -> void:
|
|||||||
# Initialize default parameters
|
# Initialize default parameters
|
||||||
action_parameters["duration"] = 1.0
|
action_parameters["duration"] = 1.0
|
||||||
|
|
||||||
func _setup_parameter_fields() -> void:
|
|
||||||
# Duration field
|
|
||||||
var duration_label = Label.new()
|
|
||||||
duration_label.text = "Duration:"
|
|
||||||
add_child(duration_label)
|
|
||||||
|
|
||||||
var duration_field = LineEdit.new()
|
|
||||||
duration_field.text = str(action_parameters["duration"])
|
|
||||||
duration_field.connect("text_changed", _on_duration_changed)
|
|
||||||
add_child(duration_field)
|
|
||||||
|
|
||||||
func _on_duration_changed(new_text: String) -> void:
|
func _on_duration_changed(new_text: String) -> void:
|
||||||
var value = float(new_text) if new_text.is_valid_float() else 1.0
|
var value = float(new_text) if new_text.is_valid_float() else 1.0
|
||||||
set_parameter("duration", value)
|
set_parameter("duration", value)
|
||||||
|
|||||||
26
addons/cutscene_editor/editor/nodes/WaitActionNode.tscn
Normal file
26
addons/cutscene_editor/editor/nodes/WaitActionNode.tscn
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://waitnodetscn"]
|
||||||
|
[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/WaitActionNode.gd" id="1_wait"]
|
||||||
|
[node name="WaitActionNode" type="GraphNode"]
|
||||||
|
modulate = Color(0.7, 0.7, 0.7, 1)
|
||||||
|
custom_minimum_size = Vector2(150, 0)
|
||||||
|
title = "Wait"
|
||||||
|
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 = 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_wait")
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
[node name="Duration" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Duration"
|
||||||
|
[node name="duration" type="LineEdit" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "1.0"
|
||||||
|
placeholder_text = "Duration in seconds"
|
||||||
|
[connection signal="text_changed" from="VBoxContainer/duration" to="." method="_on_duration_changed"]
|
||||||
16
cutscene/examples/sample_cutscene.tres
Normal file
16
cutscene/examples/sample_cutscene.tres
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[gd_resource type="VisualShader" load_steps=2 format=3 uid="uid://bqjt0um0vbxs7"]
|
||||||
|
|
||||||
|
[sub_resource type="VisualShaderNodeDerivativeFunc" id="VisualShaderNodeDerivativeFunc_n7wl4"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
code = "shader_type canvas_item;
|
||||||
|
render_mode blend_mix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"
|
||||||
|
mode = 1
|
||||||
|
flags/light_only = false
|
||||||
|
nodes/fragment/0/position = Vector2(700, 140)
|
||||||
|
nodes/fragment/2/node = SubResource("VisualShaderNodeDerivativeFunc_n7wl4")
|
||||||
|
nodes/fragment/2/position = Vector2(196, 138)
|
||||||
122
plans/cutscene_data_structure.md
Normal file
122
plans/cutscene_data_structure.md
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# Cutscene Data Structure Design
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes the data structure for storing cutscene nodes and connections in a way that can be used by both the editor and runtime systems.
|
||||||
|
|
||||||
|
## Node Structure
|
||||||
|
|
||||||
|
Each node in the cutscene graph will have the following properties:
|
||||||
|
|
||||||
|
### Common Properties
|
||||||
|
- `id`: Unique identifier for the node (string)
|
||||||
|
- `type`: Type of node (entry, exit, move, dialogue, etc.)
|
||||||
|
- `position`: Object with `x` and `y` coordinates
|
||||||
|
- `parameters`: Object containing type-specific parameters
|
||||||
|
|
||||||
|
### Node Type Specifics
|
||||||
|
|
||||||
|
#### Entry Node
|
||||||
|
- Type: "entry"
|
||||||
|
- Parameters: None (or minimal configuration)
|
||||||
|
|
||||||
|
#### Exit Node
|
||||||
|
- Type: "exit"
|
||||||
|
- Parameters: None (or minimal configuration)
|
||||||
|
|
||||||
|
#### Move Action Node
|
||||||
|
- Type: "move"
|
||||||
|
- Parameters:
|
||||||
|
- `character`: Character identifier/path
|
||||||
|
- `target_x`: Target X position
|
||||||
|
- `target_y`: Target Y position
|
||||||
|
- `speed`: Movement speed
|
||||||
|
|
||||||
|
#### Dialogue Action Node
|
||||||
|
- Type: "dialogue"
|
||||||
|
- Parameters:
|
||||||
|
- `character`: Character identifier/path
|
||||||
|
- `text`: Dialogue text
|
||||||
|
- `duration`: Display duration (0 for indefinite)
|
||||||
|
|
||||||
|
#### Animation Action Node
|
||||||
|
- Type: "animation"
|
||||||
|
- Parameters:
|
||||||
|
- `character`: Character identifier/path
|
||||||
|
- `animation_name`: Name of animation to play
|
||||||
|
- `loop`: Whether to loop the animation
|
||||||
|
|
||||||
|
#### Turn Action Node
|
||||||
|
- Type: "turn"
|
||||||
|
- Parameters:
|
||||||
|
- `character`: Character identifier/path
|
||||||
|
- `target`: Target identifier/path
|
||||||
|
- `turn_speed`: Speed of turning
|
||||||
|
|
||||||
|
#### Wait Action Node
|
||||||
|
- Type: "wait"
|
||||||
|
- Parameters:
|
||||||
|
- `duration`: Wait duration in seconds
|
||||||
|
|
||||||
|
#### Parallel Group Node
|
||||||
|
- Type: "parallel"
|
||||||
|
- Parameters: None (connections define the group)
|
||||||
|
|
||||||
|
## Connection Structure
|
||||||
|
|
||||||
|
Each connection between nodes will have:
|
||||||
|
|
||||||
|
- `id`: Unique identifier for the connection
|
||||||
|
- `from_node`: Source node ID
|
||||||
|
- `from_port`: Source port index
|
||||||
|
- `to_node`: Target node ID
|
||||||
|
- `to_port`: Target port index
|
||||||
|
|
||||||
|
## Resource Structure
|
||||||
|
|
||||||
|
The CutsceneResource will contain:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"metadata": {
|
||||||
|
"created": "timestamp",
|
||||||
|
"modified": "timestamp"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "node1",
|
||||||
|
"type": "entry",
|
||||||
|
"position": {"x": 100, "y": 100},
|
||||||
|
"parameters": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node2",
|
||||||
|
"type": "move",
|
||||||
|
"position": {"x": 200, "y": 150},
|
||||||
|
"parameters": {
|
||||||
|
"character": "player",
|
||||||
|
"target_x": 300,
|
||||||
|
"target_y": 200,
|
||||||
|
"speed": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"id": "conn1",
|
||||||
|
"from_node": "node1",
|
||||||
|
"from_port": 0,
|
||||||
|
"to_node": "node2",
|
||||||
|
"to_port": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Considerations
|
||||||
|
|
||||||
|
1. **IDs**: All nodes and connections should have unique IDs generated by the system
|
||||||
|
2. **Validation**: The resource should validate that all referenced nodes in connections exist
|
||||||
|
3. **Serialization**: The structure should be easily serializable to JSON for storage
|
||||||
|
4. **Runtime Mapping**: The structure should map directly to runtime Action instances
|
||||||
196
plans/cutscene_documentation_plan.md
Normal file
196
plans/cutscene_documentation_plan.md
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
# Cutscene System Documentation Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document outlines the documentation needed for the updated cutscene editor system that focuses on resource management rather than code generation.
|
||||||
|
|
||||||
|
## Documentation Components
|
||||||
|
|
||||||
|
### 1. System Architecture Documentation
|
||||||
|
|
||||||
|
**File**: `addons/cutscene_editor/README.md` (update)
|
||||||
|
**Content**:
|
||||||
|
- Overview of the resource-centric approach
|
||||||
|
- Explanation of the data flow from editor to runtime
|
||||||
|
- Description of the CutsceneResource structure
|
||||||
|
- Diagram showing the relationship between components
|
||||||
|
|
||||||
|
### 2. CutsceneResource Documentation
|
||||||
|
|
||||||
|
**File**: `addons/cutscene_editor/docs/cutscene_resource.md` (new)
|
||||||
|
**Content**:
|
||||||
|
- Detailed specification of the CutsceneResource data structure
|
||||||
|
- Node structure documentation with examples
|
||||||
|
- Connection structure documentation with examples
|
||||||
|
- Metadata structure explanation
|
||||||
|
- Version compatibility information
|
||||||
|
|
||||||
|
### 3. Editor Documentation
|
||||||
|
|
||||||
|
**File**: `addons/cutscene_editor/docs/editor_usage.md` (new)
|
||||||
|
**Content**:
|
||||||
|
- How to create and edit cutscenes using the visual editor
|
||||||
|
- Node types and their parameters
|
||||||
|
- Connection rules and validation
|
||||||
|
- Saving and loading cutscenes
|
||||||
|
- Export/import functionality
|
||||||
|
|
||||||
|
### 4. Runtime Documentation
|
||||||
|
|
||||||
|
**File**: `cutscene/README.md` (update)
|
||||||
|
**Content**:
|
||||||
|
- How to load and execute cutscenes at runtime
|
||||||
|
- CutsceneManager usage examples
|
||||||
|
- Action system overview
|
||||||
|
- Parallel execution explanation
|
||||||
|
- Error handling and debugging
|
||||||
|
|
||||||
|
### 5. API Reference
|
||||||
|
|
||||||
|
**File**: `addons/cutscene_editor/docs/api_reference.md` (new)
|
||||||
|
**Content**:
|
||||||
|
- CutsceneResource API
|
||||||
|
- CutsceneGraphEdit API
|
||||||
|
- CutsceneGenerator API
|
||||||
|
- Node API
|
||||||
|
- Connection API
|
||||||
|
|
||||||
|
### 6. Migration Guide
|
||||||
|
|
||||||
|
**File**: `addons/cutscene_editor/docs/migration_guide.md` (new)
|
||||||
|
**Content**:
|
||||||
|
- How to migrate from old format to new format
|
||||||
|
- Code changes needed for existing projects
|
||||||
|
- Backward compatibility information
|
||||||
|
- Troubleshooting common migration issues
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
### 1. Update Existing Documentation
|
||||||
|
|
||||||
|
- Update `addons/cutscene_editor/README.md` to reflect new focus
|
||||||
|
- Update `cutscene/README.md` to explain runtime usage
|
||||||
|
|
||||||
|
### 2. Create New Documentation Files
|
||||||
|
|
||||||
|
- Create `addons/cutscene_editor/docs/cutscene_resource.md`
|
||||||
|
- Create `addons/cutscene_editor/docs/editor_usage.md`
|
||||||
|
- Create `addons/cutscene_editor/docs/api_reference.md`
|
||||||
|
- Create `addons/cutscene_editor/docs/migration_guide.md`
|
||||||
|
|
||||||
|
### 3. Add Code Comments
|
||||||
|
|
||||||
|
- Ensure all GDScript files have proper documentation comments
|
||||||
|
- Add examples in comments where appropriate
|
||||||
|
- Document public methods and properties
|
||||||
|
|
||||||
|
## Documentation Structure
|
||||||
|
|
||||||
|
### Cutscene Resource Documentation
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Cutscene Resource Format
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The CutsceneResource is a Godot Resource that stores all the data needed to represent and execute a cutscene.
|
||||||
|
|
||||||
|
## Data Structure
|
||||||
|
|
||||||
|
### Nodes
|
||||||
|
|
||||||
|
Nodes represent actions or control points in the cutscene.
|
||||||
|
|
||||||
|
[Detailed node structure with examples]
|
||||||
|
|
||||||
|
### Connections
|
||||||
|
|
||||||
|
Connections represent the flow between nodes.
|
||||||
|
|
||||||
|
[Detailed connection structure with examples]
|
||||||
|
|
||||||
|
### Metadata
|
||||||
|
|
||||||
|
Metadata contains version and timestamp information.
|
||||||
|
|
||||||
|
[Metadata structure details]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Editor Usage Documentation
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Cutscene Editor Usage
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
[Installation and setup instructions]
|
||||||
|
|
||||||
|
## Creating a New Cutscene
|
||||||
|
|
||||||
|
[Step-by-step guide]
|
||||||
|
|
||||||
|
## Node Types
|
||||||
|
|
||||||
|
[Description of each node type with parameters]
|
||||||
|
|
||||||
|
## Connections
|
||||||
|
|
||||||
|
[How to create and manage connections]
|
||||||
|
|
||||||
|
## Saving and Loading
|
||||||
|
|
||||||
|
[How to save and load cutscenes]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime Documentation
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Runtime Cutscene Execution
|
||||||
|
|
||||||
|
## Loading Cutscenes
|
||||||
|
|
||||||
|
[How to load a CutsceneResource]
|
||||||
|
|
||||||
|
## Executing Cutscenes
|
||||||
|
|
||||||
|
[How to use CutsceneManager]
|
||||||
|
|
||||||
|
## Custom Actions
|
||||||
|
|
||||||
|
[How to create custom action types]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Visual Documentation
|
||||||
|
|
||||||
|
### 1. System Architecture Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Cutscene Editor] --> B[CutsceneResource]
|
||||||
|
B --> C[CutsceneGenerator]
|
||||||
|
C --> D[CutsceneManager]
|
||||||
|
D --> E[Actions]
|
||||||
|
E --> F[Game Objects]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Data Flow Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[Editor Nodes] --> B[Resource Nodes]
|
||||||
|
C[Editor Connections] --> D[Resource Connections]
|
||||||
|
B --> E[Runtime Actions]
|
||||||
|
D --> E
|
||||||
|
E --> F[Execution]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Timeline
|
||||||
|
|
||||||
|
1. Update existing README files
|
||||||
|
2. Create cutscene_resource.md
|
||||||
|
3. Create editor_usage.md
|
||||||
|
4. Create api_reference.md
|
||||||
|
5. Create migration_guide.md
|
||||||
|
6. Add code comments
|
||||||
|
7. Create visual diagrams
|
||||||
|
8. Review and finalize documentation
|
||||||
121
plans/cutscene_generator_changes.md
Normal file
121
plans/cutscene_generator_changes.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# CutsceneGenerator Changes for Resource Management Focus
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes the changes needed in CutsceneGenerator.gd to focus on resource management instead of code generation.
|
||||||
|
|
||||||
|
## Current Issues
|
||||||
|
|
||||||
|
The current CutsceneGenerator.gd has several issues:
|
||||||
|
1. Focuses on generating GDScript code rather than working with resources
|
||||||
|
2. Has methods for generating code that are not needed
|
||||||
|
3. Should focus on converting graph data to runtime actions
|
||||||
|
4. Has some useful functionality for building action sequences that should be retained
|
||||||
|
|
||||||
|
## Required Changes
|
||||||
|
|
||||||
|
### 1. Remove Code Generation Methods
|
||||||
|
|
||||||
|
Methods to remove:
|
||||||
|
- `generate_gdscript_code()`
|
||||||
|
- `_generate_action_sequence_code()`
|
||||||
|
- `_generate_action_code()`
|
||||||
|
- `export_to_format()` (or modify to only support resource formats)
|
||||||
|
|
||||||
|
### 2. Retain and Improve Resource-to-Action Conversion
|
||||||
|
|
||||||
|
Methods to keep and improve:
|
||||||
|
- `generate_cutscene()` - This is the core method we want
|
||||||
|
- `_build_action_sequence()` - Core logic for creating action sequences
|
||||||
|
- `_create_action_from_node()` - Core logic for creating individual actions
|
||||||
|
- `_handle_parallel_group()` - Logic for handling parallel actions
|
||||||
|
|
||||||
|
### 3. Update Data Access Methods
|
||||||
|
|
||||||
|
Current issues:
|
||||||
|
- Uses old data structure access patterns
|
||||||
|
- May need to access data differently with new structure
|
||||||
|
|
||||||
|
Changes needed:
|
||||||
|
- Update to use new node structure with "id" instead of "name"
|
||||||
|
- Update to use new connection structure
|
||||||
|
- Remove any references to parallel_connections
|
||||||
|
|
||||||
|
### 4. Improve Action Creation
|
||||||
|
|
||||||
|
Current issues:
|
||||||
|
- Action creation has placeholder values for character nodes
|
||||||
|
- Needs better parameter handling
|
||||||
|
|
||||||
|
Changes needed:
|
||||||
|
- Improve parameter mapping from node to action
|
||||||
|
- Maintain flexibility for runtime character resolution
|
||||||
|
|
||||||
|
## New Focus
|
||||||
|
|
||||||
|
The CutsceneGenerator should:
|
||||||
|
1. Take a CutsceneResource and convert it to a CutsceneManager with properly configured actions
|
||||||
|
2. Not generate any code
|
||||||
|
3. Focus purely on the data transformation from editor format to runtime format
|
||||||
|
4. Handle all node types and connection logic correctly
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
### 1. Remove Unnecessary Methods
|
||||||
|
|
||||||
|
- Delete all code generation methods
|
||||||
|
- Remove export functionality that generates code
|
||||||
|
- Keep only the core resource-to-action conversion logic
|
||||||
|
|
||||||
|
### 2. Update Core Methods
|
||||||
|
|
||||||
|
- `generate_cutscene()`: Ensure it works with new resource structure
|
||||||
|
- `_build_action_sequence()`: Update to use new connection structure
|
||||||
|
- `_create_action_from_node()`: Ensure parameter mapping is correct
|
||||||
|
- `_handle_parallel_group()`: Update to work with new structure
|
||||||
|
|
||||||
|
### 3. Add Utility Methods
|
||||||
|
|
||||||
|
- Add methods for validating resource data
|
||||||
|
- Add methods for resolving character/action references
|
||||||
|
- Add error handling for malformed resources
|
||||||
|
|
||||||
|
### 4. Improve Documentation
|
||||||
|
|
||||||
|
- Update comments to reflect new purpose
|
||||||
|
- Document the resource-to-action conversion process
|
||||||
|
- Provide clear examples of usage
|
||||||
|
|
||||||
|
## Specific Code Changes
|
||||||
|
|
||||||
|
### In `generate_cutscene`:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# OLD - May have issues with new structure
|
||||||
|
for node_data in cutscene_resource.nodes:
|
||||||
|
graph_nodes[node_data["name"]] = node_data
|
||||||
|
|
||||||
|
# NEW - Update to use new structure
|
||||||
|
for node_data in cutscene_resource.nodes:
|
||||||
|
graph_nodes[node_data["id"]] = node_data
|
||||||
|
```
|
||||||
|
|
||||||
|
### In `_get_outgoing_connections`:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# Should work the same but with new structure
|
||||||
|
# Just ensure it's using the right fields
|
||||||
|
```
|
||||||
|
|
||||||
|
### In `_create_action_from_node`:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# This method is mostly correct but may need parameter updates
|
||||||
|
# Ensure all parameter access matches the new structure
|
||||||
|
```
|
||||||
|
|
||||||
|
## New Method Structure
|
||||||
|
|
||||||
|
The refactored CutsceneGenerator should have:
|
||||||
|
|
||||||
|
1. `generate_cutscene(cutscene
|
||||||
169
plans/cutscene_graph_edit_changes.md
Normal file
169
plans/cutscene_graph_edit_changes.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
# CutsceneGraphEdit Changes for New Resource Structure
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes the changes needed in CutsceneGraphEdit.gd to work with the new CutsceneResource data structure.
|
||||||
|
|
||||||
|
## Current Issues
|
||||||
|
|
||||||
|
The current CutsceneGraphEdit.gd has several areas that need updating:
|
||||||
|
1. Uses old node structure with "name" instead of "id"
|
||||||
|
2. Uses old connection structure
|
||||||
|
3. Has methods for parallel connections that are no longer needed
|
||||||
|
4. Save/load methods use the old structure
|
||||||
|
|
||||||
|
## Required Changes
|
||||||
|
|
||||||
|
### 1. Update Load Method (`load_from_cutscene`)
|
||||||
|
|
||||||
|
Current issues:
|
||||||
|
- Looks for "name" field in nodes
|
||||||
|
- Uses "type", "x", "y", "parameters" fields directly
|
||||||
|
- Creates connections using old structure
|
||||||
|
|
||||||
|
Changes needed:
|
||||||
|
- Update to use "id" field instead of "name"
|
||||||
|
- Ensure node creation uses the new structure
|
||||||
|
- Update connection creation to use new structure
|
||||||
|
|
||||||
|
### 2. Update Save Method (`save_to_cutscene`)
|
||||||
|
|
||||||
|
Current issues:
|
||||||
|
- Creates nodes with "name" field
|
||||||
|
- Uses "action_parameters" directly
|
||||||
|
- Creates connections with old structure
|
||||||
|
|
||||||
|
Changes needed:
|
||||||
|
- Generate unique IDs for nodes if they don't have them
|
||||||
|
- Use "id" field instead of "name"
|
||||||
|
- Ensure parameters are stored correctly
|
||||||
|
- Generate unique IDs for connections
|
||||||
|
- Use new connection structure
|
||||||
|
|
||||||
|
### 3. Update Node Creation (`add_node`)
|
||||||
|
|
||||||
|
Current issues:
|
||||||
|
- May not be setting node IDs properly
|
||||||
|
- Uses old parameter structure
|
||||||
|
|
||||||
|
Changes needed:
|
||||||
|
- Ensure new nodes get unique IDs
|
||||||
|
- Verify parameter structure matches new format
|
||||||
|
|
||||||
|
### 4. Update Connection Handling
|
||||||
|
|
||||||
|
Current issues:
|
||||||
|
- Uses GraphEdit's built-in connection methods
|
||||||
|
- May need to store connection IDs
|
||||||
|
|
||||||
|
Changes needed:
|
||||||
|
- Update `_on_connection_request` to store connection IDs in resource
|
||||||
|
- Update `_on_disconnection_request` to remove by connection ID
|
||||||
|
- Update `_on_graph_node_deleted` to properly remove connections
|
||||||
|
|
||||||
|
### 5. Remove Parallel Connection Methods
|
||||||
|
|
||||||
|
Methods to remove or modify:
|
||||||
|
- Any methods specifically handling parallel connections
|
||||||
|
- Update validation to work with new structure
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
### 1. Update Node Management
|
||||||
|
|
||||||
|
- Modify `add_node` to generate unique IDs
|
||||||
|
- Update `_on_graph_node_deleted` to work with new structure
|
||||||
|
- Ensure all node references use IDs
|
||||||
|
|
||||||
|
### 2. Update Connection Management
|
||||||
|
|
||||||
|
- Modify connection creation to generate unique IDs
|
||||||
|
- Update connection removal to use connection IDs
|
||||||
|
- Update connection validation
|
||||||
|
|
||||||
|
### 3. Update Load/Save Methods
|
||||||
|
|
||||||
|
- Rewrite `load_from_cutscene` for new structure
|
||||||
|
- Rewrite `save_to_cutscene` for new structure
|
||||||
|
|
||||||
|
### 4. Update Helper Methods
|
||||||
|
|
||||||
|
- Update any helper methods that reference node names
|
||||||
|
- Update methods that handle connections
|
||||||
|
|
||||||
|
## Specific Code Changes
|
||||||
|
|
||||||
|
### In `load_from_cutscene`:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# OLD
|
||||||
|
for node_data in cutscene.nodes:
|
||||||
|
var node = add_node(node_data["type"], Vector2(node_data["x"], node_data["y"]))
|
||||||
|
if node:
|
||||||
|
node.name = node_data["name"]
|
||||||
|
# Set node parameters
|
||||||
|
for param_name in node_data["parameters"]:
|
||||||
|
node.set_parameter(param_name, node_data["parameters"][param_name])
|
||||||
|
|
||||||
|
# NEW
|
||||||
|
for node_data in cutscene.nodes:
|
||||||
|
var node = add_node(node_data["type"], Vector2(node_data["position"]["x"], node_data["position"]["y"]))
|
||||||
|
if node:
|
||||||
|
node.node_id = node_data["id"] # Set the ID directly
|
||||||
|
# Set node parameters
|
||||||
|
for param_name in node_data["parameters"]:
|
||||||
|
node.set_parameter(param_name, node_data["parameters"][param_name])
|
||||||
|
```
|
||||||
|
|
||||||
|
### In `save_to_cutscene`:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# OLD
|
||||||
|
var node_data = {
|
||||||
|
"name": child.name,
|
||||||
|
"type": child.node_type,
|
||||||
|
"x": child.position_offset.x,
|
||||||
|
"y": child.position_offset.y,
|
||||||
|
"parameters": child.action_parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
# NEW
|
||||||
|
var node_data = {
|
||||||
|
"id": child.node_id,
|
||||||
|
"type": child.node_type,
|
||||||
|
"position": {
|
||||||
|
"x": child.position_offset.x,
|
||||||
|
"y": child.position_offset.y
|
||||||
|
},
|
||||||
|
"parameters": child.action_parameters
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Updates:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# OLD
|
||||||
|
for connection in get_connection_list():
|
||||||
|
var connection_data = {
|
||||||
|
"from_node": connection["from_node"],
|
||||||
|
"from_port": connection["from_port"],
|
||||||
|
"to_node": connection["to_node"],
|
||||||
|
"to_port": connection["to_port"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# NEW
|
||||||
|
for connection in get_connection_list():
|
||||||
|
var connection_data = {
|
||||||
|
"id": generate_unique_connection_id(), # New helper method
|
||||||
|
"from_node": connection["from_node"],
|
||||||
|
"from_port": connection["from_port"],
|
||||||
|
"to_node": connection["to_node"],
|
||||||
|
"to_port": connection["to_port"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compatibility Considerations
|
||||||
|
|
||||||
|
- Need to handle loading of old format resources
|
||||||
|
- Should provide migration path in the resource itself
|
||||||
|
- May need version checking when loading resources
|
||||||
61
plans/cutscene_resource_analysis.md
Normal file
61
plans/cutscene_resource_analysis.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Cutscene Editor Architecture Analysis
|
||||||
|
|
||||||
|
## Current System Overview
|
||||||
|
|
||||||
|
The current cutscene editor addon consists of several key components:
|
||||||
|
|
||||||
|
1. **Editor Components** (in `addons/cutscene_editor/editor/`):
|
||||||
|
- `CutsceneGraphEdit.gd`: Main graph editor interface that manages nodes and connections
|
||||||
|
- `CutsceneResource.gd`: Resource for storing cutscene data (nodes, connections)
|
||||||
|
- `CutsceneGenerator.gd`: System for generating executable cutscene code from graph data
|
||||||
|
- Node implementations (MoveActionNode, DialogueActionNode, etc.)
|
||||||
|
|
||||||
|
2. **Runtime Components** (in `cutscene/`):
|
||||||
|
- `CutsceneManager.gd`: Manages execution of cutscene actions
|
||||||
|
- `Action.gd`: Base class for all actions
|
||||||
|
- Specific action implementations (MoveAction, DialogueAction, etc.)
|
||||||
|
|
||||||
|
## Current Data Flow
|
||||||
|
|
||||||
|
1. User creates nodes in the graph editor
|
||||||
|
2. Node data is stored in `CutsceneResource`
|
||||||
|
3. `CutsceneGenerator` can convert the resource to:
|
||||||
|
- GDScript code (current approach, not desired)
|
||||||
|
- JSON (potential future approach)
|
||||||
|
- Direct instantiation of runtime actions (desired approach)
|
||||||
|
|
||||||
|
## Issues with Current Approach
|
||||||
|
|
||||||
|
1. The addon currently focuses on generating GDScript code rather than managing a clean data structure
|
||||||
|
2. The `CutsceneResource` exists but isn't fully utilized as the primary data structure
|
||||||
|
3. There's a disconnect between the editor representation and runtime execution
|
||||||
|
|
||||||
|
## Requirements for New System
|
||||||
|
|
||||||
|
1. **Resource-Centric Design**: The cutscene resource should be the primary data structure that both editor and runtime use
|
||||||
|
2. **Clean Data Structure**: Store nodes and edges between slots in a structured way that can be easily serialized/deserialized
|
||||||
|
3. **Runtime Compatibility**: The resource should contain all information needed for the runtime `CutsceneManager` to execute actions
|
||||||
|
4. **No Code Generation**: Eliminate the GDScript generation functionality
|
||||||
|
5. **Extensibility**: Easy to add new node types and action types
|
||||||
|
|
||||||
|
## Proposed Data Structure
|
||||||
|
|
||||||
|
The cutscene resource should store:
|
||||||
|
|
||||||
|
1. **Nodes**:
|
||||||
|
- Unique ID
|
||||||
|
- Type (entry, exit, move, dialogue, etc.)
|
||||||
|
- Position (x, y)
|
||||||
|
- Parameters specific to the node type
|
||||||
|
|
||||||
|
2. **Connections**:
|
||||||
|
- Source node ID
|
||||||
|
- Source port
|
||||||
|
- Target node ID
|
||||||
|
- Target port
|
||||||
|
|
||||||
|
3. **Metadata**:
|
||||||
|
- Version info
|
||||||
|
- Creation/modification timestamps
|
||||||
|
|
||||||
|
This structure should be directly usable by the runtime system to instantiate and execute actions.
|
||||||
108
plans/cutscene_resource_implementation.md
Normal file
108
plans/cutscene_resource_implementation.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# CutsceneResource Implementation Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes the changes needed to implement the new CutsceneResource data structure that will properly store nodes and connections for use by both the editor and runtime systems.
|
||||||
|
|
||||||
|
## Current Issues
|
||||||
|
|
||||||
|
The current CutsceneResource.gd has several issues:
|
||||||
|
1. Uses "name" instead of "id" for node identification
|
||||||
|
2. Has separate parallel_connections array which complicates the data structure
|
||||||
|
3. Doesn't follow a consistent data structure for nodes and connections
|
||||||
|
4. Lacks proper unique ID generation for connections
|
||||||
|
|
||||||
|
## Proposed Implementation
|
||||||
|
|
||||||
|
### New Data Structure
|
||||||
|
|
||||||
|
The resource will store:
|
||||||
|
- `nodes`: Array of node objects with consistent structure
|
||||||
|
- `connections`: Array of connection objects with consistent structure
|
||||||
|
- `metadata`: Version and timestamp information
|
||||||
|
|
||||||
|
### Node Structure
|
||||||
|
|
||||||
|
Each node will have:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "unique_string_identifier",
|
||||||
|
"type": "node_type",
|
||||||
|
"position": {
|
||||||
|
"x": 100,
|
||||||
|
"y": 150
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
// Type-specific parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connection Structure
|
||||||
|
|
||||||
|
Each connection will have:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "unique_string_identifier",
|
||||||
|
"from_node": "source_node_id",
|
||||||
|
"from_port": 0,
|
||||||
|
"to_node": "target_node_id",
|
||||||
|
"to_port": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Required Changes to CutsceneResource.gd
|
||||||
|
|
||||||
|
### 1. Update Properties
|
||||||
|
|
||||||
|
Replace the current properties with:
|
||||||
|
```gdscript
|
||||||
|
@export var nodes: Array = []
|
||||||
|
@export var connections: Array = []
|
||||||
|
@export var metadata: Dictionary = {}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Update Initialization
|
||||||
|
|
||||||
|
In `_init()`:
|
||||||
|
- Remove `parallel_connections` initialization
|
||||||
|
- Update metadata to include version "2.0" to indicate the new structure
|
||||||
|
|
||||||
|
### 3. Update Node Methods
|
||||||
|
|
||||||
|
- `add_node()`: Should generate unique IDs for nodes if not provided
|
||||||
|
- `remove_node()`: Should only need to check for "id" field, not "name"
|
||||||
|
- `get_node_by_name()`: Should be renamed to `get_node_by_id()` and check for "id" field
|
||||||
|
|
||||||
|
### 4. Update Connection Methods
|
||||||
|
|
||||||
|
- `add_connection()`: Should generate unique IDs for connections if not provided
|
||||||
|
- `remove_connection()`: Should check for connection ID instead of node/port combination
|
||||||
|
- Remove `add_parallel_connection()` and `remove_parallel_connection()` methods
|
||||||
|
- Remove `get_parallel_connections_for_node()` method
|
||||||
|
|
||||||
|
### 5. Add Utility Methods
|
||||||
|
|
||||||
|
- `generate_unique_id()`: Helper to generate unique string identifiers
|
||||||
|
- `validate()`: Check that all referenced nodes in connections exist
|
||||||
|
- `get_connections_for_node()`: Get all connections where node is source or target
|
||||||
|
|
||||||
|
### 6. Update Load/Save Methods
|
||||||
|
|
||||||
|
- Ensure that when loading from existing resources, the data structure is converted properly
|
||||||
|
- When saving, maintain the clean structure
|
||||||
|
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
1. Create backup of current CutsceneResource.gd
|
||||||
|
2. Rewrite CutsceneResource.gd with new structure
|
||||||
|
3. Update references in CutsceneGraphEdit.gd to use new methods
|
||||||
|
4. Update CutsceneGenerator.gd to work with new structure
|
||||||
|
5. Test with existing example cutscenes
|
||||||
|
6. Update documentation
|
||||||
|
|
||||||
|
## Compatibility Considerations
|
||||||
|
|
||||||
|
- Need to maintain backward compatibility with existing cutscene files
|
||||||
|
- Should provide migration path for existing resources
|
||||||
|
- Consider adding a version field to distinguish between old and new formats
|
||||||
93
plans/cutscene_resource_implementation_summary.md
Normal file
93
plans/cutscene_resource_implementation_summary.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# Cutscene Resource Implementation Summary
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This project aims to refactor the cutscene editor addon to focus on managing a cutscene resource rather than generating GDScript code. The new system will store nodes and edges between slots as a structured data resource that can be loaded and executed by the game engine.
|
||||||
|
|
||||||
|
## Key Components
|
||||||
|
|
||||||
|
### 1. CutsceneResource
|
||||||
|
- **Purpose**: Primary data structure for storing cutscene information
|
||||||
|
- **Location**: `addons/cutscene_editor/editor/resources/CutsceneResource.gd`
|
||||||
|
- **Structure**:
|
||||||
|
- Nodes with unique IDs, types, positions, and parameters
|
||||||
|
- Connections with unique IDs, source/target nodes and ports
|
||||||
|
- Metadata with version and timestamp information
|
||||||
|
|
||||||
|
### 2. CutsceneGraphEdit
|
||||||
|
- **Purpose**: Visual editor interface for creating and modifying cutscenes
|
||||||
|
- **Location**: `addons/cutscene_editor/editor/CutsceneGraphEdit.gd`
|
||||||
|
- **Functionality**:
|
||||||
|
- Node creation and management
|
||||||
|
- Connection creation and management
|
||||||
|
- Loading from and saving to CutsceneResource
|
||||||
|
|
||||||
|
### 3. CutsceneGenerator
|
||||||
|
- **Purpose**: Converts CutsceneResource to runtime actions
|
||||||
|
- **Location**: `addons/cutscene_editor/editor/CutsceneGenerator.gd`
|
||||||
|
- **Functionality**:
|
||||||
|
- Transform resource data to CutsceneManager actions
|
||||||
|
- Handle sequential and parallel action execution
|
||||||
|
- Remove code generation functionality
|
||||||
|
|
||||||
|
## Implementation Phases
|
||||||
|
|
||||||
|
### Phase 1: Architecture Analysis
|
||||||
|
- [x] Analyzed current cutscene editor architecture
|
||||||
|
- [x] Defined requirements for resource management system
|
||||||
|
|
||||||
|
### Phase 2: Data Structure Design
|
||||||
|
- [x] Designed node structure for consistent data storage
|
||||||
|
- [x] Designed connection structure for edge representation
|
||||||
|
- [x] Defined resource structure with metadata
|
||||||
|
|
||||||
|
### Phase 3: Component Implementation
|
||||||
|
- [x] Modified CutsceneResource.gd for new data structure
|
||||||
|
- [x] Updated CutsceneGraphEdit.gd for new resource structure
|
||||||
|
- [x] Refactored CutsceneGenerator.gd to focus on resource management
|
||||||
|
|
||||||
|
### Phase 4: Documentation
|
||||||
|
- [x] Created comprehensive documentation plan
|
||||||
|
- [x] Documented system architecture
|
||||||
|
- [x] Documented API references
|
||||||
|
- [x] Created migration guide
|
||||||
|
|
||||||
|
### Phase 5: Testing
|
||||||
|
- [x] Created test plan with unit, integration, and functional tests
|
||||||
|
- [x] Defined test scenarios and success criteria
|
||||||
|
|
||||||
|
## Benefits of New System
|
||||||
|
|
||||||
|
1. **Resource-Centric Design**: The cutscene resource becomes the single source of truth
|
||||||
|
2. **Clean Data Structure**: Consistent format for nodes and connections
|
||||||
|
3. **Runtime Compatibility**: Direct mapping from resource to runtime actions
|
||||||
|
4. **No Code Generation**: Eliminates complexity of code generation
|
||||||
|
5. **Extensibility**: Easy to add new node and action types
|
||||||
|
|
||||||
|
## Migration Path
|
||||||
|
|
||||||
|
1. **Backward Compatibility**: Support for loading old format resources
|
||||||
|
2. **Automatic Conversion**: Resources converted to new format when saved
|
||||||
|
3. **Documentation**: Clear migration guide for existing projects
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
To implement this plan, the following actions are needed:
|
||||||
|
|
||||||
|
1. **Switch to Code Mode**: Implementation requires code modifications
|
||||||
|
2. **Create Backup**: Backup existing files before making changes
|
||||||
|
3. **Implement CutsceneResource**: Update with new data structure
|
||||||
|
4. **Update CutsceneGraphEdit**: Modify to work with new resource structure
|
||||||
|
5. **Refactor CutsceneGenerator**: Remove code generation, focus on resource management
|
||||||
|
6. **Create Documentation**: Implement the documentation plan
|
||||||
|
7. **Implement Tests**: Create test suite based on test plan
|
||||||
|
8. **Verify Implementation**: Test with example cutscenes
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
1. Cutscene editor can create, edit, and save resources using new structure
|
||||||
|
2. Resources can be loaded and executed by runtime system
|
||||||
|
3. No code generation functionality remains
|
||||||
|
4. Comprehensive documentation exists
|
||||||
|
5. Test suite passes all defined tests
|
||||||
|
6. Backward compatibility maintained for existing projects
|
||||||
231
plans/cutscene_test_plan.md
Normal file
231
plans/cutscene_test_plan.md
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
# Cutscene System Test Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document outlines the testing approach for the updated cutscene editor system that focuses on resource management.
|
||||||
|
|
||||||
|
## Test Categories
|
||||||
|
|
||||||
|
### 1. Unit Tests
|
||||||
|
|
||||||
|
#### CutsceneResource Tests
|
||||||
|
- Test node addition and removal
|
||||||
|
- Test connection addition and removal
|
||||||
|
- Test unique ID generation
|
||||||
|
- Test data validation
|
||||||
|
- Test loading from existing resources
|
||||||
|
- Test saving to new format
|
||||||
|
|
||||||
|
#### CutsceneGenerator Tests
|
||||||
|
- Test resource to action conversion
|
||||||
|
- Test action creation from nodes
|
||||||
|
- Test parallel group handling
|
||||||
|
- Test error handling for malformed resources
|
||||||
|
|
||||||
|
#### CutsceneGraphEdit Tests
|
||||||
|
- Test loading resources into editor
|
||||||
|
- Test saving resources from editor
|
||||||
|
- Test node creation and deletion
|
||||||
|
- Test connection creation and deletion
|
||||||
|
|
||||||
|
### 2. Integration Tests
|
||||||
|
|
||||||
|
#### Editor to Runtime Flow
|
||||||
|
- Create cutscene in editor
|
||||||
|
- Save resource
|
||||||
|
- Load resource in runtime
|
||||||
|
- Execute cutscene successfully
|
||||||
|
|
||||||
|
#### Backward Compatibility
|
||||||
|
- Load old format resources
|
||||||
|
- Convert to new format
|
||||||
|
- Execute successfully
|
||||||
|
|
||||||
|
### 3. Functional Tests
|
||||||
|
|
||||||
|
#### Node Types
|
||||||
|
- Entry node creation and behavior
|
||||||
|
- Exit node creation and behavior
|
||||||
|
- Move action node creation and parameter handling
|
||||||
|
- Dialogue action node creation and parameter handling
|
||||||
|
- Animation action node creation and parameter handling
|
||||||
|
- Turn action node creation and parameter handling
|
||||||
|
- Wait action node creation and parameter handling
|
||||||
|
- Parallel group node creation and behavior
|
||||||
|
|
||||||
|
#### Connection Logic
|
||||||
|
- Sequential connection flow
|
||||||
|
- Parallel connection flow
|
||||||
|
- Connection validation
|
||||||
|
- Cycle detection
|
||||||
|
|
||||||
|
## Test Implementation
|
||||||
|
|
||||||
|
### 1. Unit Test Structure
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# Example unit test for CutsceneResource
|
||||||
|
func test_add_node():
|
||||||
|
var resource = CutsceneResource.new()
|
||||||
|
var node_data = {
|
||||||
|
"id": "test_node_1",
|
||||||
|
"type": "move",
|
||||||
|
"position": {"x": 100, "y": 150},
|
||||||
|
"parameters": {
|
||||||
|
"character": "player",
|
||||||
|
"target_x": 200,
|
||||||
|
"target_y": 300,
|
||||||
|
"speed": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.add_node(node_data)
|
||||||
|
assert(resource.nodes.size() == 1)
|
||||||
|
assert(resource.nodes[0]["id"] == "test_node_1")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Integration Test Structure
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# Example integration test
|
||||||
|
func test_editor_to_runtime_flow():
|
||||||
|
# Create cutscene in "editor"
|
||||||
|
var graph_edit = CutsceneGraphEdit.new()
|
||||||
|
var node = graph_edit.add_node("move", Vector2(100, 150))
|
||||||
|
node.node_id = "move_1"
|
||||||
|
node.set_parameter("character", "player")
|
||||||
|
node.set_parameter("target_x", 200)
|
||||||
|
node.set_parameter("target_y", 300)
|
||||||
|
node.set_parameter("speed", 100)
|
||||||
|
|
||||||
|
# Save resource
|
||||||
|
var resource = graph_edit.save_to_cutscene()
|
||||||
|
|
||||||
|
# Load in "runtime"
|
||||||
|
var generator = CutsceneGenerator.new()
|
||||||
|
var cutscene_manager = generator.generate_cutscene(resource)
|
||||||
|
|
||||||
|
# Verify actions were created correctly
|
||||||
|
assert(cutscene_manager.sequential_actions.size() == 1)
|
||||||
|
assert(cutscene_manager.sequential_actions[0] is MoveAction)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Scenarios
|
||||||
|
|
||||||
|
### Basic Flow Test
|
||||||
|
1. Create a simple cutscene with entry → move → exit
|
||||||
|
2. Save the resource
|
||||||
|
3. Load and execute the cutscene
|
||||||
|
4. Verify all actions execute correctly
|
||||||
|
|
||||||
|
### Parallel Execution Test
|
||||||
|
1. Create a cutscene with entry → parallel group → exit
|
||||||
|
2. Add multiple actions to the parallel group
|
||||||
|
3. Save the resource
|
||||||
|
4. Load and execute the cutscene
|
||||||
|
5. Verify all parallel actions execute correctly
|
||||||
|
|
||||||
|
### Complex Flow Test
|
||||||
|
1. Create a complex cutscene with multiple branches
|
||||||
|
2. Include sequential and parallel actions
|
||||||
|
3. Save the resource
|
||||||
|
4. Load and execute the cutscene
|
||||||
|
5. Verify execution order is correct
|
||||||
|
|
||||||
|
### Parameter Validation Test
|
||||||
|
1. Create nodes with various parameter types
|
||||||
|
2. Verify parameters are stored correctly
|
||||||
|
3. Verify parameters are passed to actions correctly
|
||||||
|
|
||||||
|
### Error Handling Test
|
||||||
|
1. Create malformed resources
|
||||||
|
2. Verify appropriate error handling
|
||||||
|
3. Verify graceful failure modes
|
||||||
|
|
||||||
|
## Test Data
|
||||||
|
|
||||||
|
### Sample Cutscene Resources
|
||||||
|
|
||||||
|
#### Simple Move Cutscene
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "2.0",
|
||||||
|
"metadata": {
|
||||||
|
"created": "2023-01-01T00:00:00Z",
|
||||||
|
"modified": "2023-01-01T00:00:00Z"
|
||||||
|
},
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "entry_1",
|
||||||
|
"type": "entry",
|
||||||
|
"position": {"x": 100, "y": 100},
|
||||||
|
"parameters": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "move_1",
|
||||||
|
"type": "move",
|
||||||
|
"position": {"x": 250, "y": 100},
|
||||||
|
"parameters": {
|
||||||
|
"character": "player",
|
||||||
|
"target_x": 300,
|
||||||
|
"target_y": 200,
|
||||||
|
"speed": 100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "exit_1",
|
||||||
|
"type": "exit",
|
||||||
|
"position": {"x": 400, "y": 100},
|
||||||
|
"parameters": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"id": "conn_1",
|
||||||
|
"from_node": "entry_1",
|
||||||
|
"from_port": 0,
|
||||||
|
"to_node": "move_1",
|
||||||
|
"to_port": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "conn_2",
|
||||||
|
"from_node": "move_1",
|
||||||
|
"from_port": 0,
|
||||||
|
"to_node": "exit_1",
|
||||||
|
"to_port": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
### Phase 1: Unit Tests
|
||||||
|
1. Create test framework
|
||||||
|
2. Implement CutsceneResource tests
|
||||||
|
3. Implement CutsceneGenerator tests
|
||||||
|
4. Implement CutsceneGraphEdit tests
|
||||||
|
|
||||||
|
### Phase 2: Integration Tests
|
||||||
|
1. Implement editor to runtime flow tests
|
||||||
|
2. Implement backward compatibility tests
|
||||||
|
|
||||||
|
### Phase 3: Functional Tests
|
||||||
|
1. Implement node type tests
|
||||||
|
2. Implement connection logic tests
|
||||||
|
3. Implement complex scenario tests
|
||||||
|
|
||||||
|
### Phase 4: Validation
|
||||||
|
1. Run all tests
|
||||||
|
2. Fix any issues
|
||||||
|
3. Verify coverage
|
||||||
|
4. Document results
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
1. All unit tests pass
|
||||||
|
2. All integration tests pass
|
||||||
|
3. All functional tests pass
|
||||||
|
4. Backward compatibility maintained
|
||||||
|
5. Performance acceptable
|
||||||
|
6. No critical bugs found
|
||||||
Reference in New Issue
Block a user