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