This commit is contained in:
2025-07-31 18:00:00 -07:00
parent 2be97ea27c
commit 15f11fc0f3
22 changed files with 725 additions and 516 deletions

View File

@@ -76,25 +76,6 @@ func add_action(action: Action) -> void:
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
@@ -120,7 +101,7 @@ func _execute_next_action() -> void:
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

View File

@@ -1,7 +1,7 @@
# Cutscene System for Godot 4.3
## Overview
This is a flexible cutscene system for 2D point-and-click adventure games in Godot 4.3. It supports both sequential and parallel action execution, with a focus on extensibility and dynamic behavior.
This is a flexible cutscene system for 2D point-and-click adventure games in Godot 4.3. It supports both sequential and parallel action execution, with a focus on extensibility and dynamic behavior. The system can be used directly with code or with the visual Cutscene Editor plugin that manages cutscene resources.
## Features
- Sequential action execution
@@ -9,6 +9,7 @@ This is a flexible cutscene system for 2D point-and-click adventure games in God
- Extensible action system
- Signal-based completion system
- Error handling and recovery
- Resource-based cutscene management (with Cutscene Editor plugin)
## System Components
@@ -25,7 +26,7 @@ This is a flexible cutscene system for 2D point-and-click adventure games in God
## Usage
### Basic Setup
### Basic Setup (Code-based)
```gdscript
# Create a cutscene manager
var cutscene_manager = CutsceneManager.new()
@@ -39,7 +40,7 @@ cutscene_manager.add_action(DialogueAction.new(character, "Hello, world!"))
cutscene_manager.start()
```
### Parallel Actions
### Parallel Actions (Code-based)
```gdscript
# Create parallel actions
var parallel_actions = [
@@ -49,6 +50,20 @@ var parallel_actions = [
cutscene_manager.add_parallel_actions(parallel_actions)
```
### Resource-based Setup (With Cutscene Editor)
```gdscript
# Load a cutscene resource created with the visual editor
var cutscene_resource = preload("res://path/to/your/cutscene.tscn")
# Generate actions from the resource
var generator = CutsceneGenerator.new()
var cutscene_manager = generator.generate_cutscene(cutscene_resource)
# Add to scene and start
add_child(cutscene_manager)
cutscene_manager.start()
```
### The Example Scenario
The system supports complex sequences like the one described in the requirements:

View File

@@ -19,6 +19,7 @@ func _init(character_node: Node2D, target: Vector2, move_speed: float = 100.0) -
name = "MoveAction"
func start() -> void:
print("started", character)
if character == null:
self._set_failed("Character is null")
return
@@ -29,6 +30,7 @@ func start() -> void:
self._set_running()
func update(delta: float) -> void:
print ("updating")
if state != State.RUNNING:
return

View File

@@ -1,10 +0,0 @@
[gd_scene format=3 uid="uid://animatedcharacter"]
[ext_resource type="Script" path="res://cutscene/examples/animated_character.gd" id="1"]
[node name="AnimatedCharacter" type="Node2D"]
script = ExtResource( "1" )
[node name="Sprite2D" type="Sprite2D" parent="."]
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]

View File

@@ -1,80 +0,0 @@
extends Node2D
# Character nodes
@onready var character1: Node2D = $Character1
@onready var character2: Node2D = $Character2
# Cutscene manager
var cutscene_manager: CutsceneManager
func _ready() -> void:
# Initialize the cutscene system
setup_cutscene()
# Start the cutscene after a short delay to see the initial positions
var start_timer = Timer.new()
start_timer.wait_time = 1.0
start_timer.one_shot = true
start_timer.connect("timeout", start_cutscene)
add_child(start_timer)
start_timer.start()
func setup_cutscene() -> void:
# Create the cutscene manager
cutscene_manager = CutsceneManager.new()
add_child(cutscene_manager)
# Connect to cutscene signals
cutscene_manager.connect("cutscene_started", _on_cutscene_started)
cutscene_manager.connect("cutscene_completed", _on_cutscene_completed)
cutscene_manager.connect("action_started", _on_action_started)
cutscene_manager.connect("action_completed", _on_action_completed)
# Create the action sequence as described in requirements
# 1. & 2. Characters move simultaneously
var parallel_moves = [
MoveAction.new(character1, Vector2(234, 591), 100.0), # Character1 moves
MoveAction.new(character2, Vector2(912, 235), 100.0) # Character2 moves
]
cutscene_manager.add_parallel_actions(parallel_moves)
# 3. Character2 turns to face Character1
var turn_action = TurnAction.new(character2, character1, 1.0)
cutscene_manager.add_action(turn_action)
# 4. Character2 says dialogue
var dialogue_action = DialogueAction.new(character2, "Hello there, friend!", 2.0)
cutscene_manager.add_action(dialogue_action)
# 5. Character1 plays shocked animation (simulated with a wait since we don't have an actual animation)
var animation_action = WaitAction.new(1.0) # Simulate animation with wait
cutscene_manager.add_action(animation_action)
# Add a final dialogue from character1
var final_dialogue = DialogueAction.new(character1, "That was surprising!", 2.0)
cutscene_manager.add_action(final_dialogue)
func start_cutscene() -> void:
print("Starting cutscene...")
cutscene_manager.start()
func _on_cutscene_started() -> void:
print("Cutscene started!")
func _on_cutscene_completed() -> void:
print("Cutscene completed!")
print("Final positions:")
print("Character1: %s" % character1.position)
print("Character2: %s" % character2.position)
func _on_action_started(action: Action) -> void:
print("Action started: %s" % action.name)
func _on_action_completed(action: Action) -> void:
print("Action completed: %s" % action.name)
# Clean up when the node is removed
func _exit_tree() -> void:
if cutscene_manager:
cutscene_manager.queue_free()

View File

@@ -1,16 +0,0 @@
[gd_resource type="VisualShader" load_steps=2 format=3 uid="uid://bqjt0um0vbxs7"]
[sub_resource type="VisualShaderNodeDerivativeFunc" id="VisualShaderNodeDerivativeFunc_n7wl4"]
[resource]
code = "shader_type canvas_item;
render_mode blend_mix;
"
mode = 1
flags/light_only = false
nodes/fragment/0/position = Vector2(700, 140)
nodes/fragment/2/node = SubResource("VisualShaderNodeDerivativeFunc_n7wl4")
nodes/fragment/2/position = Vector2(196, 138)

View File

@@ -1,18 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://bx826fm1kd3wk"]
[ext_resource type="Script" path="res://cutscene/examples/sample_cutscene.gd" id="1"]
[node name="SampleCutscene" type="Node2D"]
script = ExtResource("1")
[node name="Character1" type="Node2D" parent="."]
position = Vector2(100, 100)
[node name="Polygon2D" type="Polygon2D" parent="Character1"]
polygon = PackedVector2Array(-5, -19, -27, 2, 2, 15, 15, 6, 9, -19)
[node name="Character2" type="Node2D" parent="."]
position = Vector2(200, 100)
[node name="Polygon2D" type="Polygon2D" parent="Character2"]
polygon = PackedVector2Array(10, -25, -43, 1, -14, 40, 48, 13)

View File

@@ -1,95 +0,0 @@
extends Node2D
# Test the cutscene system
func _ready() -> void:
print("Testing cutscene system...")
# Create test characters
var char1 = Node2D.new()
char1.name = "TestCharacter1"
add_child(char1)
var char2 = Node2D.new()
char2.name = "TestCharacter2"
add_child(char2)
# Create animation player for char1
var anim_player = AnimationPlayer.new()
anim_player.name = "AnimationPlayer"
char1.add_child(anim_player)
# Create a simple animation
var animation = Animation.new()
animation.name = "test_animation"
animation.length = 1.0
anim_player.add_animation("test_animation", animation)
# Test the cutscene system
test_sequential_actions(char1, char2)
# After a delay, test parallel actions
var timer = Timer.new()
timer.wait_time = 3.0
timer.one_shot = true
timer.connect("timeout", test_parallel_actions.bind(char1, char2))
add_child(timer)
timer.start()
func test_sequential_actions(char1: Node2D, char2: Node2D) -> void:
print("\n=== Testing Sequential Actions ===")
# Create cutscene manager
var manager = CutsceneManager.new()
add_child(manager)
# Connect signals
manager.connect("cutscene_completed", _on_test_completed.bind("sequential"))
# Add sequential actions
manager.add_action(MoveAction.new(char1, Vector2(100, 100), 50.0))
manager.add_action(WaitAction.new(0.5))
manager.add_action(TurnAction.new(char1, Vector2(200, 200), 1.0))
manager.add_action(DialogueAction.new(char1, "Hello, world!", 1.0))
manager.add_action(AnimationAction.new(char1, "test_animation", false))
# Start the cutscene
manager.start()
func test_parallel_actions(char1: Node2D, char2: Node2D) -> void:
print("\n=== Testing Parallel Actions ===")
# Create cutscene manager
var manager = CutsceneManager.new()
add_child(manager)
# Connect signals
manager.connect("cutscene_completed", _on_test_completed.bind("parallel"))
# Add parallel actions
var parallel_group = [
MoveAction.new(char1, Vector2(300, 300), 100.0),
MoveAction.new(char2, Vector2(400, 400), 100.0)
]
manager.add_parallel_actions(parallel_group)
# Add sequential actions after parallel
manager.add_action(TurnAction.new(char1, char2, 2.0))
manager.add_action(DialogueAction.new(char1, "We moved together!", 1.5))
# Start the cutscene
manager.start()
func _on_test_completed(test_type: String) -> void:
print("Test %s completed successfully!" % test_type)
# Clean up after a delay
var cleanup_timer = Timer.new()
cleanup_timer.wait_time = 1.0
cleanup_timer.one_shot = true
cleanup_timer.connect("timeout", clean_up)
add_child(cleanup_timer)
cleanup_timer.start()
func clean_up() -> void:
print("\n=== All tests completed ===")
print("Cutscene system is working correctly!")