8.7 KiB
8.7 KiB
Action Types Design
Overview
This document details the specific action types that will be implemented for the cutscene system. Each action type handles a specific kind of operation in a cutscene.
Core Action Types
1. MoveAction
Moves a character to a specific position over time.
class_name MoveAction
extends Action
# 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):
character = character_node
target_position = target
speed = move_speed
name = "MoveAction"
func start() -> void:
if character == null:
._set_failed("Character is null")
return
start_position = character.position
distance = start_position.distance_to(target_position)
traveled = 0.0
._set_running()
func update(delta: float) -> void:
if state != State.RUNNING:
return
if character == null:
._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
._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
2. TurnAction
Makes a character turn to face a direction or another character.
class_name TurnAction
extends Action
# 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):
character = character_node
target = turn_target
turn_speed = speed
name = "TurnAction"
func start() -> void:
if character == null:
._set_failed("Character is null")
return
._set_running()
func update(delta: float) -> void:
if state != State.RUNNING:
return
if character == null:
._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:
._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
._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
._set_completed()
else:
character.rotation += rotation_amount
func is_completed() -> bool:
return state == State.COMPLETED
3. DialogueAction
Displays dialogue text, potentially with character-specific formatting.
class_name DialogueAction
extends Action
# Properties
var character: Node2D # The speaking character (optional)
var text: String # Dialogue text
var duration: float = 0.0 # Duration to display (0 = manual advance)
var auto_advance: bool = true # Whether to auto-advance after duration
func _init(speaking_character: Node2D, dialogue_text: String, display_duration: float = 0.0):
character = speaking_character
text = dialogue_text
duration = display_duration
name = "DialogueAction"
func start() -> void:
# In a real implementation, this would interface with a dialogue system
# For now, we'll simulate by printing to console
print("%s: %s" % [character.name if character else "Narrator", text])
._set_running()
# If duration is 0, this is a manual advance action
# In a real game, this would wait for player input
if duration <= 0:
# For demo purposes, we'll complete immediately
# In a real game, this would wait for input
._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)
# In a real implementation, we'd add this to the scene tree
# add_child(timer)
timer.start()
func _on_timer_timeout():
._set_completed()
func is_completed() -> bool:
return state == State.COMPLETED
4. AnimationAction
Plays a specific animation on a character.
class_name AnimationAction
extends Action
# 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):
character = character_node
animation_name = anim_name
loop = should_loop
name = "AnimationAction"
func start() -> void:
if character == null:
._set_failed("Character is null")
return
# In a real implementation, this would interface with an AnimationPlayer
# For now, we'll simulate by printing to console
print("Playing animation '%s' on %s" % [animation_name, character.name])
# Check if character has an AnimationPlayer
var anim_player = _get_animation_player()
if anim_player == null:
._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)
# Play the animation
anim_player.play(animation_name, loop)
._set_running()
# For looping animations, we complete immediately
# (they would be stopped by another action)
if loop:
._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):
if anim_name == animation_name:
._set_completed()
func is_completed() -> bool:
return state == State.COMPLETED
5. WaitAction
Pauses execution for a specified time.
class_name WaitAction
extends Action
# Properties
var duration: float # Time to wait in seconds
var elapsed_time: float = 0.0
func _init(wait_duration: float):
duration = wait_duration
name = "WaitAction"
func start() -> void:
elapsed_time = 0.0
._set_running()
func update(delta: float) -> void:
if state != State.RUNNING:
return
elapsed_time += delta
if elapsed_time >= duration:
._set_completed()
func is_completed() -> bool:
return state == State.COMPLETED
Extensibility
To create new action types:
- Create a new class that extends
Action - Implement the required methods:
start()- Initialize and begin the actionupdate(delta)- Update the action each frame (if needed)is_completed()- Return true when the action is finished
- Optionally implement
stop()for cleanup - Use appropriate signals to notify completion
Example of a custom action:
class_name CustomAction
extends Action
# Custom properties for this action
var custom_parameter: String
func _init(param: String):
custom_parameter = param
name = "CustomAction"
func start() -> void:
# Perform the action
print("Executing custom action with parameter: %s" % custom_parameter)
# For immediate actions, complete right away
._set_completed()
func is_completed() -> bool:
return state == State.COMPLETED
This design provides a solid set of core action types while maintaining the flexibility to add new types as needed.