288 lines
7.9 KiB
GDScript
288 lines
7.9 KiB
GDScript
@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
|
|
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()
|
|
func _parameters_to_view() -> void:
|
|
pass
|