initial
This commit is contained in:
55
cutscene/actions/AnimationAction.gd
Normal file
55
cutscene/actions/AnimationAction.gd
Normal file
@@ -0,0 +1,55 @@
|
||||
class_name AnimationAction
|
||||
extends "res://cutscene/Action.gd"
|
||||
|
||||
# Properties
|
||||
var character: Node2D # The character to animate
|
||||
var animation_name: String # Name of the animation to play
|
||||
var loop: bool = false # Whether to loop the animation
|
||||
|
||||
func _init(character_node: Node2D, anim_name: String, should_loop: bool = false) -> void:
|
||||
character = character_node
|
||||
animation_name = anim_name
|
||||
loop = should_loop
|
||||
name = "AnimationAction"
|
||||
|
||||
func start() -> void:
|
||||
if character == null:
|
||||
self._set_failed("Character is null")
|
||||
return
|
||||
|
||||
# Check if character has an AnimationPlayer
|
||||
var anim_player = _get_animation_player()
|
||||
if anim_player == null:
|
||||
self._set_failed("Character has no AnimationPlayer")
|
||||
return
|
||||
|
||||
# Connect to animation finished signal for non-looping animations
|
||||
if not loop:
|
||||
if not anim_player.is_connected("animation_finished", _on_animation_finished):
|
||||
anim_player.connect("animation_finished", _on_animation_finished.bind(anim_player))
|
||||
|
||||
# Play the animation
|
||||
anim_player.play(animation_name)
|
||||
self._set_running()
|
||||
|
||||
# For looping animations, we complete immediately
|
||||
# (they would be stopped by another action)
|
||||
if loop:
|
||||
self._set_completed()
|
||||
|
||||
func _get_animation_player() -> AnimationPlayer:
|
||||
# Try to find AnimationPlayer as a child
|
||||
for child in character.get_children():
|
||||
if child is AnimationPlayer:
|
||||
return child
|
||||
|
||||
# Try to find AnimationPlayer in the scene tree
|
||||
return character.get_node_or_null("AnimationPlayer") as AnimationPlayer
|
||||
|
||||
func _on_animation_finished(anim_name: String, anim_player: AnimationPlayer) -> void:
|
||||
# Make sure this is for our animation
|
||||
if anim_name == animation_name and not loop:
|
||||
self._set_completed()
|
||||
|
||||
func is_completed() -> bool:
|
||||
return state == State.COMPLETED
|
||||
75
cutscene/actions/DialogueAction.gd
Normal file
75
cutscene/actions/DialogueAction.gd
Normal file
@@ -0,0 +1,75 @@
|
||||
class_name DialogueAction
|
||||
extends "res://cutscene/Action.gd"
|
||||
|
||||
# Properties
|
||||
var character: Node2D # The speaking character (optional)
|
||||
var text: String # Dialogue text
|
||||
var duration: float = 0.0 # Duration to display (0 = manual advance)
|
||||
|
||||
func _init(speaking_character: Node2D, dialogue_text: String, display_duration: float = 0.0) -> void:
|
||||
character = speaking_character
|
||||
text = dialogue_text
|
||||
duration = display_duration
|
||||
name = "DialogueAction"
|
||||
|
||||
func start() -> void:
|
||||
# Display the dialogue text
|
||||
_display_dialogue()
|
||||
self._set_running()
|
||||
|
||||
# If duration is 0, this is a manual advance action
|
||||
if duration <= 0:
|
||||
# For demo purposes, we'll complete immediately
|
||||
# In a real game, this would wait for player input
|
||||
self._set_completed()
|
||||
else:
|
||||
# Start a timer for automatic completion
|
||||
var timer = Timer.new()
|
||||
timer.wait_time = duration
|
||||
timer.one_shot = true
|
||||
timer.connect("timeout", _on_timer_timeout)
|
||||
|
||||
# Add timer as a child to ensure it processes
|
||||
if Engine.get_main_loop().current_scene:
|
||||
Engine.get_main_loop().current_scene.add_child(timer)
|
||||
#else:
|
||||
## Fallback if we can't access the main scene
|
||||
#var root = get_tree().root if get_tree() else null
|
||||
#if root and root.get_child_count() > 0:
|
||||
#root.get_child(0).add_child(timer)
|
||||
#else:
|
||||
## Last resort - connect directly and manage manually
|
||||
#timer.connect("timeout", _on_timer_timeout_direct)
|
||||
#timer.start(duration)
|
||||
#return
|
||||
|
||||
timer.connect("timeout", _cleanup_timer.bind(timer))
|
||||
timer.start()
|
||||
|
||||
func _display_dialogue() -> void:
|
||||
# In a real implementation, this would interface with a dialogue system
|
||||
# For now, we'll simulate by printing to console
|
||||
var character_name = character.name if character and character.name else "Unknown"
|
||||
print("%s: %s" % [character_name, text])
|
||||
|
||||
func _on_timer_timeout() -> void:
|
||||
self._set_completed()
|
||||
|
||||
func _on_timer_timeout_direct() -> void:
|
||||
# Direct timeout handler for when we can't add the timer to the scene tree
|
||||
self._set_completed()
|
||||
|
||||
func _cleanup_timer(timer: Timer) -> void:
|
||||
# Clean up the timer
|
||||
if timer and timer.get_parent():
|
||||
timer.get_parent().remove_child(timer)
|
||||
if timer:
|
||||
timer.queue_free()
|
||||
self._set_completed()
|
||||
|
||||
func is_completed() -> bool:
|
||||
return state == State.COMPLETED
|
||||
|
||||
func stop() -> void:
|
||||
# Clean up any timers when stopping
|
||||
super.stop()
|
||||
54
cutscene/actions/MoveAction.gd
Normal file
54
cutscene/actions/MoveAction.gd
Normal file
@@ -0,0 +1,54 @@
|
||||
class_name MoveAction
|
||||
extends "res://cutscene/Action.gd"
|
||||
|
||||
# Properties
|
||||
var character: Node2D # The character to move
|
||||
var target_position: Vector2 # Target position
|
||||
var speed: float = 100.0 # Movement speed (pixels/second)
|
||||
var threshold: float = 5.0 # Distance threshold for completion
|
||||
|
||||
# Internal
|
||||
var start_position: Vector2
|
||||
var distance: float
|
||||
var traveled: float = 0.0
|
||||
|
||||
func _init(character_node: Node2D, target: Vector2, move_speed: float = 100.0) -> void:
|
||||
character = character_node
|
||||
target_position = target
|
||||
speed = move_speed
|
||||
name = "MoveAction"
|
||||
|
||||
func start() -> void:
|
||||
if character == null:
|
||||
self._set_failed("Character is null")
|
||||
return
|
||||
|
||||
start_position = character.position
|
||||
distance = start_position.distance_to(target_position)
|
||||
traveled = 0.0
|
||||
self._set_running()
|
||||
|
||||
func update(delta: float) -> void:
|
||||
if state != State.RUNNING:
|
||||
return
|
||||
|
||||
if character == null:
|
||||
self._set_failed("Character was destroyed during action")
|
||||
return
|
||||
|
||||
# Calculate movement for this frame
|
||||
var frame_distance = speed * delta
|
||||
traveled += frame_distance
|
||||
|
||||
# If we've reached or overshot the target
|
||||
if traveled >= distance:
|
||||
character.position = target_position
|
||||
self._set_completed()
|
||||
return
|
||||
|
||||
# Move character along the path
|
||||
var direction = (target_position - start_position).normalized()
|
||||
character.position = start_position + direction * traveled
|
||||
|
||||
func is_completed() -> bool:
|
||||
return state == State.COMPLETED
|
||||
69
cutscene/actions/TurnAction.gd
Normal file
69
cutscene/actions/TurnAction.gd
Normal file
@@ -0,0 +1,69 @@
|
||||
class_name TurnAction
|
||||
extends "res://cutscene/Action.gd"
|
||||
|
||||
# Properties
|
||||
var character: Node2D # The character to turn
|
||||
var target: Variant # Either a Vector2 position or another Node2D
|
||||
var turn_speed: float = 2.0 # Rotation speed (radians/second)
|
||||
|
||||
func _init(character_node: Node2D, turn_target: Variant, speed: float = 2.0) -> void:
|
||||
character = character_node
|
||||
target = turn_target
|
||||
turn_speed = speed
|
||||
name = "TurnAction"
|
||||
|
||||
func start() -> void:
|
||||
if character == null:
|
||||
self._set_failed("Character is null")
|
||||
return
|
||||
self._set_running()
|
||||
|
||||
func update(delta: float) -> void:
|
||||
if state != State.RUNNING:
|
||||
return
|
||||
|
||||
if character == null:
|
||||
self._set_failed("Character was destroyed during action")
|
||||
return
|
||||
|
||||
# Calculate target rotation
|
||||
var target_position: Vector2
|
||||
if target is Vector2:
|
||||
target_position = target
|
||||
elif target is Node2D:
|
||||
target_position = target.position
|
||||
else:
|
||||
self._set_failed("Invalid target type")
|
||||
return
|
||||
|
||||
var direction = target_position - character.position
|
||||
var target_rotation = atan2(direction.y, direction.x)
|
||||
|
||||
# Rotate toward target
|
||||
var angle_diff = _angle_difference(character.rotation, target_rotation)
|
||||
|
||||
# If we're close enough, complete the action
|
||||
if abs(angle_diff) < 0.01:
|
||||
character.rotation = target_rotation
|
||||
self._set_completed()
|
||||
return
|
||||
|
||||
# Rotate based on turn speed
|
||||
var rotation_amount = sign(angle_diff) * turn_speed * delta
|
||||
if abs(rotation_amount) > abs(angle_diff):
|
||||
character.rotation = target_rotation
|
||||
self._set_completed()
|
||||
else:
|
||||
character.rotation += rotation_amount
|
||||
|
||||
func is_completed() -> bool:
|
||||
return state == State.COMPLETED
|
||||
|
||||
# Helper function to calculate angle difference
|
||||
func _angle_difference(from: float, to: float) -> float:
|
||||
var diff = fmod(to - from, 2.0 * PI)
|
||||
if diff < -PI:
|
||||
diff += 2.0 * PI
|
||||
elif diff > PI:
|
||||
diff -= 2.0 * PI
|
||||
return diff
|
||||
25
cutscene/actions/WaitAction.gd
Normal file
25
cutscene/actions/WaitAction.gd
Normal file
@@ -0,0 +1,25 @@
|
||||
class_name WaitAction
|
||||
extends "res://cutscene/Action.gd"
|
||||
|
||||
# Properties
|
||||
var duration: float # Time to wait in seconds
|
||||
var elapsed_time: float = 0.0
|
||||
|
||||
func _init(wait_duration: float) -> void:
|
||||
duration = wait_duration
|
||||
name = "WaitAction"
|
||||
|
||||
func start() -> void:
|
||||
elapsed_time = 0.0
|
||||
self._set_running()
|
||||
|
||||
func update(delta: float) -> void:
|
||||
if state != State.RUNNING:
|
||||
return
|
||||
|
||||
elapsed_time += delta
|
||||
if elapsed_time >= duration:
|
||||
self._set_completed()
|
||||
|
||||
func is_completed() -> bool:
|
||||
return state == State.COMPLETED
|
||||
Reference in New Issue
Block a user