Files
experiment-adventure-ai/cutscene/CutsceneManager.gd
2025-07-31 18:00:00 -07:00

210 lines
6.0 KiB
GDScript

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)
# 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
print(action_item)
# 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