This commit is contained in:
Bryce
2025-08-01 08:34:51 -07:00
parent 15f11fc0f3
commit 44d3f10875
77 changed files with 605 additions and 713 deletions

196
cutscene/CutsceneManager.gd Normal file → Executable file
View File

@@ -1,14 +1,13 @@
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
# Action dependency graph
var actions: Dictionary = {} # Map of action IDs to action instances
var dependencies: Dictionary = {} # Map of action IDs to their dependency lists
var dependents: Dictionary = {} # Map of action IDs to actions that depend on them
var ready_actions: Array = [] # Actions that are ready to execute (all dependencies met)
var active_actions: Array = [] # Currently running actions
var completed_actions: Array = [] # Actions that have completed
# State management
enum State {
@@ -39,8 +38,16 @@ func start() -> void:
is_active = true
emit_signal("cutscene_started")
# Start first action
_execute_next_action()
# Find actions with no dependencies to start with
_find_ready_actions()
# Start all ready actions
for action_id in ready_actions:
_execute_action(action_id)
# Check if there are no actions to execute
if actions.size() == 0:
_on_cutscene_completed()
func pause() -> void:
# Pause the current cutscene
@@ -56,67 +63,78 @@ func resume() -> void:
func stop() -> void:
# Stop the current cutscene and reset
if current_action != null:
current_action.stop()
current_action = null
# Stop all active actions
for action in active_actions:
if action.state == action.State.RUNNING:
action.stop()
# Stop all active parallel groups
for group in active_parallel_groups:
for action in group["actions"]:
if action.state == action.State.RUNNING:
action.stop()
active_actions.clear()
_reset()
func add_action(action: Action) -> void:
# Add a single action to the sequential queue
func add_action(action_id: String, action: Action, deps: Array = []) -> void:
# Add an action with its dependencies
if state != State.IDLE:
print("Warning: Cannot add actions while cutscene is running")
return
sequential_actions.append(action)
actions[action_id] = action
dependencies[action_id] = deps
# Build reverse dependency map (dependents)
for dep_id in deps:
if not dependents.has(dep_id):
dependents[dep_id] = []
dependents[dep_id].append(action_id)
# Internal methods
func _process(delta: float) -> void:
# Main update loop
if state != State.RUNNING:
return
# Find actions with no dependencies to start with
_find_ready_actions()
# 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)
# Start all ready actions
for action_id in ready_actions:
_execute_action(action_id)
# Update all active actions
for action in active_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
func _find_ready_actions() -> void:
# Find actions that are ready to execute (all dependencies met)
ready_actions.clear()
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)
for action_id in actions:
# Skip if already completed or active
if completed_actions.has(action_id) or active_actions.has(actions[action_id]):
continue
# Check if all dependencies are met
var all_deps_met = true
for dep_id in dependencies[action_id]:
if not completed_actions.has(dep_id):
all_deps_met = false
break
func _execute_single_action(action: Action) -> void:
if all_deps_met:
ready_actions.append(action_id)
func _execute_action(action_id: String) -> void:
# Execute a single action
current_action = action
var action = actions[action_id]
# Remove from ready actions
ready_actions.erase(action_id)
# Add to active actions
active_actions.append(action)
# Connect to action signals
if not action.is_connected("completed", _on_action_completed):
action.connect("completed", _on_action_completed.bind(action))
action.connect("completed", _on_action_completed.bind(action_id))
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):
@@ -126,72 +144,37 @@ func _execute_single_action(action: Action) -> void:
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:
func _on_action_completed(action_id: String) -> void:
# Handle action completion
if action == current_action:
current_action = null
emit_signal("action_completed", action)
# Move to next action
_execute_next_action()
var action = actions[action_id]
active_actions.erase(action)
completed_actions.append(action_id)
emit_signal("action_completed", action)
# Check if all actions are completed
if completed_actions.size() == actions.size():
_on_cutscene_completed()
else:
# Find newly ready actions
_find_ready_actions()
# Start all newly ready actions
for new_action_id in ready_actions:
_execute_action(new_action_id)
func _on_action_failed(action: Action, error_message: String) -> void:
# Handle action failure
if action == current_action:
current_action = null
active_actions.erase(action)
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
@@ -200,10 +183,11 @@ func _on_cutscene_completed() -> void:
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
actions.clear()
dependencies.clear()
dependents.clear()
ready_actions.clear()
active_actions.clear()
completed_actions.clear()
state = State.IDLE
is_active = false