class_name CutsceneManager extends Node # Action queues var sequential_actions: Array = [] # Actions that run one after another var current_action: Action = null # The action currently being executed var action_index: int = 0 # Index of the next sequential action # Parallel actions var parallel_groups: Array = [] # Groups of actions running simultaneously var active_parallel_groups: Array = [] # Currently running parallel action groups # State management enum State { IDLE, # Not running any cutscene RUNNING, # Currently executing a cutscene PAUSED # Cutscene is paused } var state: int = State.IDLE var is_active: bool = false # Signals signal cutscene_started() signal cutscene_completed() signal cutscene_paused() signal cutscene_resumed() signal action_started(action) signal action_completed(action) signal action_failed(action, error_message) # Public methods func start() -> void: # Start executing the cutscene if state != State.IDLE: return state = State.RUNNING is_active = true emit_signal("cutscene_started") # Start first action _execute_next_action() func pause() -> void: # Pause the current cutscene if state == State.RUNNING: state = State.PAUSED emit_signal("cutscene_paused") func resume() -> void: # Resume a paused cutscene if state == State.PAUSED: state = State.RUNNING emit_signal("cutscene_resumed") func stop() -> void: # Stop the current cutscene and reset if current_action != null: current_action.stop() current_action = null # Stop all active parallel groups for group in active_parallel_groups: for action in group["actions"]: if action.state == action.State.RUNNING: action.stop() _reset() func add_action(action: Action) -> void: # Add a single action to the sequential queue if state != State.IDLE: print("Warning: Cannot add actions while cutscene is running") return sequential_actions.append(action) func add_parallel_actions(actions: Array) -> void: # Add a group of actions to run in parallel if state != State.IDLE: print("Warning: Cannot add actions while cutscene is running") return if actions.size() == 0: return # Create a parallel action group var group = { "actions": actions, "completed_count": 0, "total_count": actions.size() } # Add to sequential actions as a single item sequential_actions.append(group) # Internal methods func _process(delta: float) -> void: # Main update loop if state != State.RUNNING: return # Update current sequential action if current_action != null and current_action.state == current_action.State.RUNNING: current_action.update(delta) # Update active parallel groups for group in active_parallel_groups: for action in group["actions"]: if action.state == action.State.RUNNING: action.update(delta) func _execute_next_action() -> void: # Start executing the next sequential action if action_index >= sequential_actions.size(): # No more actions, cutscene complete _on_cutscene_completed() return var action_item = sequential_actions[action_index] action_index += 1 # Check if this is a parallel group or single action if typeof(action_item) == TYPE_DICTIONARY and action_item.has("actions"): # This is a parallel group _execute_parallel_group(action_item) else: # This is a single action _execute_single_action(action_item) func _execute_single_action(action: Action) -> void: # Execute a single action current_action = action # Connect to action signals if not action.is_connected("completed", _on_action_completed): action.connect("completed", _on_action_completed.bind(action)) if not action.is_connected("failed", _on_action_failed): action.connect("failed", _on_action_failed.bind(action)) if not action.is_connected("started", _on_action_started): action.connect("started", _on_action_started.bind(action)) # Start the action emit_signal("action_started", action) action.start() func _execute_parallel_group(group: Dictionary) -> void: # Execute a group of parallel actions var actions = group["actions"] # Reset completion count group["completed_count"] = 0 # Add to active parallel groups active_parallel_groups.append(group) # Connect to each action's signals for action in actions: if not action.is_connected("completed", _on_parallel_action_completed): action.connect("completed", _on_parallel_action_completed.bind(group, action)) if not action.is_connected("failed", _on_parallel_action_failed): action.connect("failed", _on_parallel_action_failed.bind(group, action)) if not action.is_connected("started", _on_action_started): action.connect("started", _on_action_started.bind(action)) # Emit started signal and start action emit_signal("action_started", action) action.start() func _on_action_started(action: Action) -> void: # Handle action started emit_signal("action_started", action) func _on_action_completed(action: Action) -> void: # Handle action completion if action == current_action: current_action = null emit_signal("action_completed", action) # Move to next action _execute_next_action() func _on_action_failed(action: Action, error_message: String) -> void: # Handle action failure if action == current_action: current_action = null emit_signal("action_failed", action, error_message) print("Action failed: %s - %s" % [action.name, error_message]) # Stop the cutscene stop() func _on_parallel_action_completed(group: Dictionary, action: Action) -> void: # Increment completed count group["completed_count"] += 1 emit_signal("action_completed", action) # Check if all actions in group are completed if group["completed_count"] >= group["total_count"]: # Remove from active groups active_parallel_groups.erase(group) # Continue with next sequential action _execute_next_action() func _on_parallel_action_failed(group: Dictionary, action: Action, error_message: String) -> void: # Handle parallel action failure emit_signal("action_failed", action, error_message) print("Parallel action failed: %s - %s" % [action.name, error_message]) # Stop the cutscene stop() func _on_cutscene_completed() -> void: # Handle cutscene completion state = State.IDLE is_active = false emit_signal("cutscene_completed") func _reset() -> void: # Reset the manager to initial state sequential_actions.clear() parallel_groups.clear() active_parallel_groups.clear() current_action = null action_index = 0 state = State.IDLE is_active = false