progress.
This commit is contained in:
62
addons/cutscene_editor/editor/nodes/AnimationActionNode.gd
Normal file
62
addons/cutscene_editor/editor/nodes/AnimationActionNode.gd
Normal file
@@ -0,0 +1,62 @@
|
||||
@tool
|
||||
class_name AnimationActionNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Node for AnimationAction
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "animation"
|
||||
node_id = "animation_" + str(randi())
|
||||
title = "Animation"
|
||||
modulate = Color(0.8, 0.4, 0.8) # Purple
|
||||
|
||||
# One input and one output connection
|
||||
var slot = 0
|
||||
set_slot(slot, true, 0, Color(0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Initialize default parameters
|
||||
action_parameters["character"] = ""
|
||||
action_parameters["animation_name"] = ""
|
||||
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:
|
||||
set_parameter("character", new_text)
|
||||
|
||||
func _on_animation_changed(new_text: String) -> void:
|
||||
set_parameter("animation_name", new_text)
|
||||
|
||||
func _on_loop_toggled(button_pressed: bool) -> void:
|
||||
set_parameter("loop", button_pressed)
|
||||
284
addons/cutscene_editor/editor/nodes/BaseGraphNode.gd
Normal file
284
addons/cutscene_editor/editor/nodes/BaseGraphNode.gd
Normal file
@@ -0,0 +1,284 @@
|
||||
@tool
|
||||
class_name BaseGraphNode
|
||||
extends GraphNode
|
||||
|
||||
# Base class for all cutscene graph nodes
|
||||
|
||||
# Signals
|
||||
signal node_selected2(node)
|
||||
signal node_deleted(node)
|
||||
signal parameter_changed(node, parameter_name, new_value)
|
||||
|
||||
# Node states
|
||||
enum NodeState {
|
||||
IDLE,
|
||||
ACTIVE,
|
||||
COMPLETED,
|
||||
ERROR,
|
||||
PAUSED
|
||||
}
|
||||
|
||||
# Properties
|
||||
var node_type: String = "base"
|
||||
var node_id: String # Unique identifier for the node
|
||||
var action_parameters: Dictionary = {} # Stores parameter values
|
||||
var current_state: int = NodeState.IDLE
|
||||
var error_message: String = ""
|
||||
var property_editors: Dictionary = {} # Map of property names to editors
|
||||
|
||||
# Visual feedback elements
|
||||
var state_border: ColorRect
|
||||
var overlay_icon: TextureRect
|
||||
var checkmark_texture: Texture2D
|
||||
var error_texture: Texture2D
|
||||
var pause_texture: Texture2D
|
||||
|
||||
# Called when the node is ready
|
||||
func _ready() -> void:
|
||||
# Set up common node properties
|
||||
connect("dragged", _on_node_dragged)
|
||||
connect("selected", _on_node_selected)
|
||||
|
||||
# Add close butto
|
||||
|
||||
# Set up visual feedback elements
|
||||
_setup_visual_feedback()
|
||||
|
||||
# Add parameter fields based on node type
|
||||
_setup_parameter_fields()
|
||||
|
||||
# Set up visual feedback elements
|
||||
func _setup_visual_feedback() -> void:
|
||||
# Create state border
|
||||
state_border = ColorRect.new()
|
||||
state_border.name = "StateBorder"
|
||||
state_border.anchor_right = 1
|
||||
state_border.anchor_bottom = 1
|
||||
state_border.margin_left = -2
|
||||
state_border.margin_top = -2
|
||||
state_border.margin_right = 2
|
||||
state_border.margin_bottom = 2
|
||||
state_border.color = Color(0, 0, 0, 0) # Transparent by default
|
||||
state_border.z_index = -1 # Behind the node
|
||||
add_child(state_border)
|
||||
|
||||
# Create overlay icon container
|
||||
var overlay_container = CenterContainer.new()
|
||||
overlay_container.name = "OverlayContainer"
|
||||
overlay_container.anchor_right = 1
|
||||
overlay_container.anchor_bottom = 1
|
||||
overlay_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(overlay_container)
|
||||
|
||||
# Create overlay icon
|
||||
overlay_icon = TextureRect.new()
|
||||
overlay_icon.name = "OverlayIcon"
|
||||
overlay_icon.expand = true
|
||||
overlay_icon.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
overlay_icon.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
overlay_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
overlay_container.add_child(overlay_icon)
|
||||
|
||||
# Load textures (these would be actual textures in a real implementation)
|
||||
# checkmark_texture = preload("res://addons/cutscene_editor/icons/checkmark.png")
|
||||
# error_texture = preload("res://addons/cutscene_editor/icons/error.png")
|
||||
# pause_texture = preload("res://addons/cutscene_editor/icons/pause.png")
|
||||
|
||||
# Set up parameter fields based on node type
|
||||
func _setup_parameter_fields() -> void:
|
||||
# This method should be overridden by subclasses
|
||||
pass
|
||||
|
||||
# Set node state and update visual feedback
|
||||
func set_state(new_state: int, error_msg: String = "") -> void:
|
||||
current_state = new_state
|
||||
error_message = error_msg
|
||||
_update_visual_feedback()
|
||||
|
||||
# Update visual feedback based on current state
|
||||
func _update_visual_feedback() -> void:
|
||||
match current_state:
|
||||
NodeState.IDLE:
|
||||
_set_idle_state()
|
||||
NodeState.ACTIVE:
|
||||
_set_active_state()
|
||||
NodeState.COMPLETED:
|
||||
_set_completed_state()
|
||||
NodeState.ERROR:
|
||||
_set_error_state()
|
||||
NodeState.PAUSED:
|
||||
_set_paused_state()
|
||||
|
||||
# Set idle state visuals
|
||||
func _set_idle_state() -> void:
|
||||
# Reset to default appearance
|
||||
state_border.color = Color(0, 0, 0, 0)
|
||||
overlay_icon.texture = null
|
||||
modulate = Color(1, 1, 1, 1)
|
||||
scale = Vector2(1, 1)
|
||||
|
||||
# Stop any animations
|
||||
_stop_animations()
|
||||
|
||||
# Set active state visuals
|
||||
func _set_active_state() -> void:
|
||||
# White border highlight
|
||||
state_border.color = Color(1, 1, 1, 1)
|
||||
state_border.size = Vector2(2, 2)
|
||||
|
||||
# Clear overlay
|
||||
overlay_icon.texture = null
|
||||
|
||||
# Start pulsing animation
|
||||
_start_pulsing_animation()
|
||||
|
||||
# Slight scale increase
|
||||
scale = Vector2(1.05, 1.05)
|
||||
|
||||
# Set completed state visuals
|
||||
func _set_completed_state() -> void:
|
||||
# Green border
|
||||
state_border.color = Color(0, 1, 0, 0.5)
|
||||
state_border.size = Vector2(2, 2)
|
||||
|
||||
# Checkmark overlay
|
||||
overlay_icon.texture = checkmark_texture
|
||||
overlay_icon.modulate = Color(0, 1, 0, 0.7)
|
||||
|
||||
# Slight transparency
|
||||
modulate = Color(1, 1, 1, 0.8)
|
||||
|
||||
# Stop animations
|
||||
_stop_animations()
|
||||
|
||||
# Set error state visuals
|
||||
func _set_error_state() -> void:
|
||||
# Red border
|
||||
state_border.color = Color(1, 0, 0, 1)
|
||||
state_border.size = Vector2(3, 3)
|
||||
|
||||
# Error icon overlay
|
||||
overlay_icon.texture = error_texture
|
||||
overlay_icon.modulate = Color(1, 0, 0, 1)
|
||||
|
||||
# Red tint
|
||||
modulate = Color(1, 0.7, 0.7, 1)
|
||||
|
||||
# Start shake animation
|
||||
_start_shake_animation()
|
||||
|
||||
# Set paused state visuals
|
||||
func _set_paused_state() -> void:
|
||||
# Yellow border
|
||||
state_border.color = Color(1, 1, 0, 1)
|
||||
state_border.size = Vector2(2, 2)
|
||||
|
||||
# Pause icon overlay
|
||||
overlay_icon.texture = pause_texture
|
||||
overlay_icon.modulate = Color(1, 1, 0, 1)
|
||||
|
||||
# Stop animations
|
||||
_stop_animations()
|
||||
|
||||
# Animation functions
|
||||
func _start_pulsing_animation() -> void:
|
||||
# Create animation player for pulsing effect
|
||||
var anim_player = AnimationPlayer.new()
|
||||
anim_player.name = "StateAnimationPlayer"
|
||||
|
||||
# Remove existing animation player if present
|
||||
var existing_player = get_node_or_null("StateAnimationPlayer")
|
||||
if existing_player:
|
||||
remove_child(existing_player)
|
||||
existing_player.queue_free()
|
||||
|
||||
add_child(anim_player)
|
||||
|
||||
# Create pulsing animation
|
||||
var animation = Animation.new()
|
||||
animation.name = "pulse"
|
||||
animation.length = 1.0
|
||||
animation.loop_mode = Animation.LOOP_LINEAR
|
||||
|
||||
# Scale property track
|
||||
var scale_track = animation.add_track(Animation.TYPE_VALUE)
|
||||
animation.track_set_path(scale_track, ".:scale")
|
||||
animation.track_insert_key(scale_track, 0.0, Vector2(1.05, 1.05))
|
||||
animation.track_insert_key(scale_track, 0.5, Vector2(1.1, 1.1))
|
||||
animation.track_insert_key(scale_track, 1.0, Vector2(1.05, 1.05))
|
||||
|
||||
anim_player.add_animation("pulse", animation)
|
||||
anim_player.play("pulse")
|
||||
|
||||
func _start_shake_animation() -> void:
|
||||
# Create animation player for shake effect
|
||||
var anim_player = AnimationPlayer.new()
|
||||
anim_player.name = "StateAnimationPlayer"
|
||||
|
||||
# Remove existing animation player if present
|
||||
var existing_player = get_node_or_null("StateAnimationPlayer")
|
||||
if existing_player:
|
||||
remove_child(existing_player)
|
||||
existing_player.queue_free()
|
||||
|
||||
add_child(anim_player)
|
||||
|
||||
# Create shake animation
|
||||
var animation = Animation.new()
|
||||
animation.name = "shake"
|
||||
animation.length = 0.5
|
||||
animation.loop_mode = Animation.LOOP_LINEAR
|
||||
|
||||
# Position property track
|
||||
var position_track = animation.add_track(Animation.TYPE_VALUE)
|
||||
animation.track_set_path(position_track, ".:position_offset")
|
||||
animation.track_insert_key(position_track, 0.0, position_offset)
|
||||
animation.track_insert_key(position_track, 0.1, position_offset + Vector2(2, 0))
|
||||
animation.track_insert_key(position_track, 0.2, position_offset + Vector2(-2, 0))
|
||||
animation.track_insert_key(position_track, 0.3, position_offset + Vector2(0, 2))
|
||||
animation.track_insert_key(position_track, 0.4, position_offset + Vector2(0, -2))
|
||||
animation.track_insert_key(position_track, 0.5, position_offset)
|
||||
|
||||
anim_player.add_animation("shake", animation)
|
||||
anim_player.play("shake")
|
||||
|
||||
func _stop_animations() -> void:
|
||||
var anim_player = get_node_or_null("StateAnimationPlayer")
|
||||
if anim_player:
|
||||
anim_player.stop()
|
||||
|
||||
# Update parameter value
|
||||
func set_parameter(parameter_name: String, value) -> void:
|
||||
action_parameters[parameter_name] = value
|
||||
|
||||
# Update editor if it exists
|
||||
if property_editors.has(parameter_name):
|
||||
var editor = property_editors[parameter_name]
|
||||
editor.set_value(value)
|
||||
|
||||
emit_signal("parameter_changed", self, parameter_name, value)
|
||||
|
||||
# Get parameter value
|
||||
func get_parameter(parameter_name: String):
|
||||
return action_parameters.get(parameter_name, null)
|
||||
|
||||
# Handle node dragging
|
||||
func _on_node_dragged(from: Vector2, to: Vector2) -> void:
|
||||
# Update position
|
||||
position_offset = to
|
||||
|
||||
# Handle node selection
|
||||
func _on_node_selected() -> void:
|
||||
emit_signal("node_selected2", self)
|
||||
|
||||
|
||||
# Clear parameter fields
|
||||
func _clear_parameter_fields() -> void:
|
||||
# Remove existing editors
|
||||
for param_name in property_editors:
|
||||
var editor = property_editors[param_name]
|
||||
if editor.get_parent() == self:
|
||||
remove_child(editor)
|
||||
editor.queue_free()
|
||||
|
||||
property_editors.clear()
|
||||
68
addons/cutscene_editor/editor/nodes/DialogueActionNode.gd
Normal file
68
addons/cutscene_editor/editor/nodes/DialogueActionNode.gd
Normal file
@@ -0,0 +1,68 @@
|
||||
@tool
|
||||
class_name DialogueActionNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Node for DialogueAction
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "dialogue"
|
||||
node_id = "dialogue_" + str(randi())
|
||||
title = "Dialogue"
|
||||
modulate = Color(1.0, 1.0, 0.5) # Yellow
|
||||
resizable=true
|
||||
# One input and one output connection
|
||||
var slot = 0
|
||||
set_slot(slot, true, 0, Color(0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Initialize default parameters
|
||||
action_parameters["character"] = ""
|
||||
action_parameters["text"] = ""
|
||||
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:
|
||||
set_parameter("character", new_text)
|
||||
|
||||
func _on_text_changed() -> void:
|
||||
var text_edit = get_child(get_child_count() - 2) # TextEdit is second to last child
|
||||
set_parameter("text", text_edit.text)
|
||||
|
||||
func _on_duration_changed(new_text: String) -> void:
|
||||
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
||||
set_parameter("duration", value)
|
||||
20
addons/cutscene_editor/editor/nodes/EntryNode.gd
Normal file
20
addons/cutscene_editor/editor/nodes/EntryNode.gd
Normal file
@@ -0,0 +1,20 @@
|
||||
@tool
|
||||
class_name EntryNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Entry point for the cutscene
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "entry"
|
||||
node_id = "entry_" + str(randi())
|
||||
title = "Start"
|
||||
modulate = Color(0.5, 1.0, 0.5) # Light green
|
||||
|
||||
# Entry node has no input connections
|
||||
# Add one output connection point
|
||||
var output_slot = 0
|
||||
set_slot(output_slot, false, 0, Color(0, 0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Entry node has no parameter fields
|
||||
20
addons/cutscene_editor/editor/nodes/ExitNode.gd
Normal file
20
addons/cutscene_editor/editor/nodes/ExitNode.gd
Normal file
@@ -0,0 +1,20 @@
|
||||
@tool
|
||||
class_name ExitNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Exit point for the cutscene
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "exit"
|
||||
node_id = "exit_" + str(randi())
|
||||
title = "End"
|
||||
modulate = Color(1.0, 0.5, 0.5) # Light red
|
||||
|
||||
# Exit node has one input connection
|
||||
# No output connections
|
||||
var input_slot = 0
|
||||
set_slot(input_slot, true, 0, Color(0, 0, 0), false, 0, Color(0, 0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Exit node has no parameter fields
|
||||
88
addons/cutscene_editor/editor/nodes/MoveActionNode.gd
Normal file
88
addons/cutscene_editor/editor/nodes/MoveActionNode.gd
Normal file
@@ -0,0 +1,88 @@
|
||||
@tool
|
||||
class_name MoveActionNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Node for MoveAction
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "move"
|
||||
node_id = "move_" + str(randi())
|
||||
title = "Move"
|
||||
modulate = Color(0.4, 0.6, 1.0) # Blue
|
||||
|
||||
# One input and one output connection
|
||||
var slot = 0
|
||||
set_slot(slot, true, 0, Color(0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Initialize default parameters
|
||||
action_parameters["character"] = ""
|
||||
action_parameters["target_x"] = 0.0
|
||||
action_parameters["target_y"] = 0.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:
|
||||
set_parameter("character", new_text)
|
||||
|
||||
func _on_target_x_changed(new_text: String) -> void:
|
||||
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
||||
set_parameter("target_x", value)
|
||||
|
||||
func _on_target_y_changed(new_text: String) -> void:
|
||||
var value = float(new_text) if new_text.is_valid_float() else 0.0
|
||||
set_parameter("target_y", value)
|
||||
|
||||
func _on_speed_changed(new_text: String) -> void:
|
||||
var value = float(new_text) if new_text.is_valid_float() else 100.0
|
||||
set_parameter("speed", value)
|
||||
126
addons/cutscene_editor/editor/nodes/ParallelGroupNode.gd
Normal file
126
addons/cutscene_editor/editor/nodes/ParallelGroupNode.gd
Normal file
@@ -0,0 +1,126 @@
|
||||
@tool
|
||||
class_name ParallelGroupNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Node for grouping parallel actions
|
||||
|
||||
# Special properties for parallel groups
|
||||
var input_connections: int = 3 # Number of input connection points
|
||||
var child_nodes: Array = [] # Child nodes contained within this group
|
||||
var is_container: bool = true # Flag to indicate this is a container node
|
||||
|
||||
# Visual properties
|
||||
var container_rect: PanelContainer # Visual container for child nodes
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "parallel"
|
||||
node_id = "parallel_" + str(randi())
|
||||
title = "Parallel Group"
|
||||
modulate = Color(1.0, 0.6, 0.2) # Orange
|
||||
|
||||
# Set up slots for connections
|
||||
_setup_slots()
|
||||
|
||||
# Set up container for child nodes
|
||||
_setup_container()
|
||||
|
||||
# Set up connection slots
|
||||
func _setup_slots() -> void:
|
||||
# Multiple input connections for parallel actions
|
||||
for i in range(input_connections):
|
||||
set_slot(i, true, 0, Color(0, 0, 0), false, 0, Color(0, 0, 0, 0))
|
||||
|
||||
# Single output connection for sequential continuation
|
||||
var output_slot = input_connections
|
||||
set_slot(output_slot, false, 0, Color(0, 0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
# Set up visual container for child nodes
|
||||
func _setup_container() -> void:
|
||||
# Create container panel
|
||||
container_rect = PanelContainer.new()
|
||||
container_rect.name = "Container"
|
||||
container_rect.anchor_right = 1
|
||||
container_rect.anchor_bottom = 1
|
||||
container_rect.margin_top = 30 # Leave space for title bar
|
||||
container_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
# Set container style
|
||||
var style = StyleBoxFlat.new()
|
||||
style.bg_color = Color(0.9, 0.9, 0.9, 0.3)
|
||||
style.border_color = Color(0.5, 0.5, 0.5, 0.5)
|
||||
style.border_width_left = 1
|
||||
style.border_width_top = 1
|
||||
style.border_width_right = 1
|
||||
style.border_width_bottom = 1
|
||||
container_rect.add_theme_stylebox_override("panel", style)
|
||||
|
||||
add_child(container_rect)
|
||||
|
||||
# Create container for child nodes
|
||||
var child_container = VBoxContainer.new()
|
||||
child_container.name = "ChildContainer"
|
||||
child_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
container_rect.add_child(child_container)
|
||||
|
||||
# Add a child node to this parallel group
|
||||
func add_child_node(child_node: BaseGraphNode) -> void:
|
||||
# Add to child nodes array
|
||||
child_nodes.append(child_node)
|
||||
|
||||
# Add as child in scene tree
|
||||
if container_rect and container_rect.has_node("ChildContainer"):
|
||||
container_rect.get_node("ChildContainer").add_child(child_node)
|
||||
|
||||
# Update visual representation
|
||||
_update_container_size()
|
||||
|
||||
# Remove a child node from this parallel group
|
||||
func remove_child_node(child_node: BaseGraphNode) -> void:
|
||||
# Remove from child nodes array
|
||||
child_nodes.erase(child_node)
|
||||
|
||||
# Remove from scene tree
|
||||
if child_node.get_parent() == container_rect.get_node("ChildContainer"):
|
||||
container_rect.get_node("ChildContainer").remove_child(child_node)
|
||||
|
||||
# Update visual representation
|
||||
_update_container_size()
|
||||
|
||||
# Update container size based on child nodes
|
||||
func _update_container_size() -> void:
|
||||
# Calculate required size based on child nodes
|
||||
var required_height = 20 # Minimum height
|
||||
|
||||
if container_rect and container_rect.has_node("ChildContainer"):
|
||||
var child_container = container_rect.get_node("ChildContainer")
|
||||
for child in child_container.get_children():
|
||||
if child is BaseGraphNode:
|
||||
required_height += child.size.y + 5 # Add spacing
|
||||
|
||||
# Update container size
|
||||
container_rect.custom_minimum_size.y = required_height
|
||||
|
||||
# Handle node dragging
|
||||
func _on_node_dragged(from: Vector2, to: Vector2) -> void:
|
||||
# Update position
|
||||
position_offset = to
|
||||
|
||||
# Update child nodes if they're positioned relative to this node
|
||||
for child in child_nodes:
|
||||
# Child nodes should move with the parallel group
|
||||
pass
|
||||
|
||||
# Add more input connections if needed
|
||||
func add_input_connection() -> void:
|
||||
var slot_index = input_connections
|
||||
set_slot(slot_index, true, 0, Color(0, 0, 0), false, 0, Color(0, 0, 0, 0))
|
||||
input_connections += 1
|
||||
|
||||
# Get the output slot index
|
||||
func get_output_slot_index() -> int:
|
||||
return input_connections
|
||||
|
||||
# Check if a node can be added as a child
|
||||
func can_add_child_node(node: BaseGraphNode) -> bool:
|
||||
# Can't add entry, exit, or other parallel groups as children
|
||||
return node.node_type != "entry" and node.node_type != "exit" and node.node_type != "parallel"
|
||||
63
addons/cutscene_editor/editor/nodes/TurnActionNode.gd
Normal file
63
addons/cutscene_editor/editor/nodes/TurnActionNode.gd
Normal file
@@ -0,0 +1,63 @@
|
||||
@tool
|
||||
class_name TurnActionNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Node for TurnAction
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "turn"
|
||||
node_id = "turn_" + str(randi())
|
||||
title = "Turn"
|
||||
modulate = Color(0.5, 1.0, 0.5) # Green
|
||||
|
||||
# One input and one output connection
|
||||
var slot = 0
|
||||
set_slot(slot, true, 0, Color(0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Initialize default parameters
|
||||
action_parameters["character"] = ""
|
||||
action_parameters["target"] = ""
|
||||
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:
|
||||
set_parameter("character", new_text)
|
||||
|
||||
func _on_target_changed(new_text: String) -> void:
|
||||
set_parameter("target", new_text)
|
||||
|
||||
func _on_turn_speed_changed(new_text: String) -> void:
|
||||
var value = float(new_text) if new_text.is_valid_float() else 2.0
|
||||
set_parameter("turn_speed", value)
|
||||
35
addons/cutscene_editor/editor/nodes/WaitActionNode.gd
Normal file
35
addons/cutscene_editor/editor/nodes/WaitActionNode.gd
Normal file
@@ -0,0 +1,35 @@
|
||||
@tool
|
||||
class_name WaitActionNode
|
||||
extends "res://addons/cutscene_editor/editor/nodes/BaseGraphNode.gd"
|
||||
|
||||
# Node for WaitAction
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "wait"
|
||||
node_id = "wait_" + str(randi())
|
||||
title = "Wait"
|
||||
modulate = Color(0.7, 0.7, 0.7) # Gray
|
||||
|
||||
# One input and one output connection
|
||||
var slot = 0
|
||||
set_slot(slot, true, 0, Color(0, 0, 0), true, 0, Color(0, 0, 0))
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
# Initialize default parameters
|
||||
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:
|
||||
var value = float(new_text) if new_text.is_valid_float() else 1.0
|
||||
set_parameter("duration", value)
|
||||
Reference in New Issue
Block a user