Rework player state system to use an event subscription system to avoid directly calling methods on individual state and having to worry about validity
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
extends Node
|
||||
|
||||
@export var state_machine: PlayerStateMachine
|
||||
|
||||
# Public Methods
|
||||
func OnMovementInput(_movement_vector: Vector2) -> void:
|
||||
var current_state := state_machine.GetCurrentStateEnum()
|
||||
if current_state == PlayerStateMachine.States.IDLE:
|
||||
var idle_state := state_machine.current_state as PlayerIdleState
|
||||
idle_state.QueueMovement()
|
||||
@@ -3,8 +3,11 @@ extends Node
|
||||
|
||||
@export var state_machine: PlayerStateMachine
|
||||
|
||||
var _subscribed_events: Array[String] = []
|
||||
var _subscribed_events_callables: Array[Callable] = []
|
||||
|
||||
func GetStateEnum() -> PlayerStateMachine.States:
|
||||
push_error("Unimplemented Method: BaseState.GetName")
|
||||
push_error("Unimplemented Method: BaseState.GetStateEnum")
|
||||
return PlayerStateMachine.States.IDLE
|
||||
|
||||
|
||||
@@ -31,3 +34,23 @@ func IsActive() -> bool:
|
||||
|
||||
func IsStateActionable() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
func SubscribeToEvent(event_name: String, callback: Callable) -> void:
|
||||
if _subscribed_events.has(event_name):
|
||||
return
|
||||
_subscribed_events.append(event_name)
|
||||
_subscribed_events_callables.append(callback)
|
||||
|
||||
|
||||
# State Machine Visibility Only
|
||||
func _StateMachine_OnEventSent(event_name: String, parameters: Variant) -> void:
|
||||
var idx := _subscribed_events.find(event_name)
|
||||
if idx == -1:
|
||||
push_error("THIS SHOULD NEVER HAPPEN LOL")
|
||||
|
||||
var callable := _subscribed_events_callables[idx]
|
||||
if callable.get_argument_count() == 0:
|
||||
callable.call()
|
||||
else:
|
||||
callable.call(parameters)
|
||||
|
||||
@@ -1,52 +1,14 @@
|
||||
extends BaseState
|
||||
class_name PlayerIdleState
|
||||
|
||||
signal PlayerBecameIdle
|
||||
# idle_state.gd
|
||||
|
||||
@export var player: PlayerCharacter
|
||||
func _ready() -> void:
|
||||
SubscribeToEvent("MovementQueued", OnMovementQueued)
|
||||
|
||||
var _movement_component: MovementComponent
|
||||
var _sit_queued := false
|
||||
var _sit_queue_pos: Vector2
|
||||
var _sit_queue_dir: Enums.Directions
|
||||
|
||||
func OnMovementQueued(dv: Vector2) -> void:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.WALKING, {"dv": dv})
|
||||
|
||||
|
||||
func GetStateEnum() -> PlayerStateMachine.States:
|
||||
return PlayerStateMachine.States.IDLE
|
||||
|
||||
|
||||
func Enter(_extra_parameters: Dictionary) -> void:
|
||||
_movement_component = ComponentUtils.GetMovementComponent(player)
|
||||
if not _movement_component:
|
||||
print_rich("[color=yellow]Warning: Player does not have a movement component...[/color]")
|
||||
|
||||
PlayerBecameIdle.emit()
|
||||
|
||||
|
||||
func Update(_delta: float) -> void:
|
||||
var item_a := Input.is_action_just_pressed("use_item_a")
|
||||
|
||||
if item_a:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.USING_ITEM_A, {})
|
||||
return
|
||||
|
||||
if _sit_queued:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.SITTING, {"pos": _sit_queue_pos, "dir": _sit_queue_dir})
|
||||
_sit_queued = false
|
||||
return
|
||||
|
||||
if _movement_component and _movement_component.movement_vector != Vector2.ZERO:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.WALKING)
|
||||
|
||||
|
||||
func OnSitOnFurnitureTriggered(sitting_position: Vector2, sitting_direction: Enums.Directions) -> void:
|
||||
if state_machine.GetCurrentStateEnum() != GetStateEnum():
|
||||
return
|
||||
|
||||
_sit_queued = true
|
||||
_sit_queue_pos = sitting_position
|
||||
_sit_queue_dir = sitting_direction
|
||||
|
||||
|
||||
func OnCutsceneStarted() -> void:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.CUTSCENE)
|
||||
|
||||
@@ -1,30 +1,41 @@
|
||||
extends BaseState
|
||||
|
||||
# walking_state.gd
|
||||
|
||||
signal StartedWalking
|
||||
|
||||
@export var walking_speed := 100
|
||||
@export var direction_component: FacingDirectionComponent
|
||||
@export var body: CharacterBody2D
|
||||
|
||||
var _movement_component: MovementComponent
|
||||
var _queued_dv: Vector2
|
||||
|
||||
func GetStateEnum() -> PlayerStateMachine.States:
|
||||
return PlayerStateMachine.States.WALKING
|
||||
func _ready() -> void:
|
||||
SubscribeToEvent("MovementQueued", OnMovementQueued)
|
||||
SubscribeToEvent("NoMovementQueued", OnNoMovementQueued)
|
||||
|
||||
|
||||
func Enter(_extra_parameters: Dictionary) -> void:
|
||||
_movement_component = ComponentUtils.GetMovementComponent(body)
|
||||
print("Walking State Entered")
|
||||
_queued_dv = _extra_parameters["dv"]
|
||||
StartedWalking.emit()
|
||||
|
||||
|
||||
func Update(_delta: float) -> void:
|
||||
var movement_vector := _movement_component.movement_vector
|
||||
|
||||
if movement_vector == Vector2.ZERO:
|
||||
if _queued_dv == Vector2.ZERO:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.IDLE)
|
||||
return
|
||||
|
||||
body.velocity = movement_vector * walking_speed
|
||||
body.velocity = _queued_dv * walking_speed
|
||||
body.move_and_slide()
|
||||
|
||||
direction_component.ChangeDirectionUsingMovementVector(movement_vector)
|
||||
|
||||
|
||||
func OnMovementQueued(dv: Vector2) -> void:
|
||||
_queued_dv = dv
|
||||
|
||||
|
||||
func OnNoMovementQueued() -> void:
|
||||
_queued_dv = Vector2.ZERO
|
||||
|
||||
|
||||
func GetStateEnum() -> PlayerStateMachine.States:
|
||||
return PlayerStateMachine.States.WALKING
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
extends Node
|
||||
class_name MovementComponent
|
||||
|
||||
signal MovementInput(movement_vector: Vector2)
|
||||
|
||||
var movement_vector: Vector2
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var direction_vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
|
||||
|
||||
if direction_vector:
|
||||
movement_vector = direction_vector
|
||||
MovementInput.emit(movement_vector)
|
||||
else:
|
||||
movement_vector = Vector2.ZERO
|
||||
@@ -1 +0,0 @@
|
||||
uid://dwclkwbig1uii
|
||||
@@ -1,18 +0,0 @@
|
||||
extends CharacterBody2D
|
||||
class_name PlayerCharacter
|
||||
|
||||
# Signals
|
||||
signal SitOnFurnitureTriggered(sitting_position: Vector2, sitting_direction: Enums.Directions)
|
||||
|
||||
# Exports
|
||||
@export var player_sprite: PlayerSprite
|
||||
@export var state_machine: PlayerStateMachine
|
||||
@export var interact_scanner: InteractScanner
|
||||
|
||||
# Public Methods
|
||||
func QueueCutsceneState() -> void:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.CUTSCENE)
|
||||
|
||||
|
||||
func QueueEndCutsceneState() -> void:
|
||||
state_machine.QueueStateChange(PlayerStateMachine.States.IDLE)
|
||||
4
Entities/Characters/Player/Scripts/player_body.gd
Normal file
4
Entities/Characters/Player/Scripts/player_body.gd
Normal file
@@ -0,0 +1,4 @@
|
||||
extends CharacterBody2D
|
||||
|
||||
# PlayerBody.gd:
|
||||
# Represents the player's actual CharacterBody (collision)
|
||||
@@ -1,4 +1,4 @@
|
||||
extends Node2D
|
||||
extends AnimatedSprite2D
|
||||
class_name PlayerSprite
|
||||
|
||||
# Signals
|
||||
@@ -6,37 +6,11 @@ signal DrawingBowAnimationFinished
|
||||
signal FiringArrowAnimationFinished
|
||||
signal AnimationFinished(animation_name: String)
|
||||
|
||||
# Exports
|
||||
@export var state_machine: PlayerStateMachine
|
||||
@export var direction_component: FacingDirectionComponent
|
||||
|
||||
# OnReady Variables
|
||||
@onready var full: AnimatedSprite2D = $Full
|
||||
|
||||
# Private Variables
|
||||
var _all_parts: Array[AnimatedSprite2D]
|
||||
var _current_animation := "idle-down"
|
||||
var _is_flipped := false
|
||||
|
||||
# Public Methods
|
||||
func UpdateSprite() -> void:
|
||||
var current_state := state_machine.current_state
|
||||
var current_direction := direction_component.GetCurrentDirection()
|
||||
var animation := _build_animation_name(current_state, current_direction)
|
||||
var should_flip := _should_flip_horizontal()
|
||||
|
||||
if animation == _current_animation and should_flip == _is_flipped:
|
||||
return
|
||||
|
||||
_current_animation = animation
|
||||
_is_flipped = should_flip
|
||||
|
||||
for part in _all_parts:
|
||||
part.animation = animation
|
||||
part.play()
|
||||
part.flip_h = should_flip
|
||||
|
||||
|
||||
func OnAnimationFinished() -> void:
|
||||
if _current_animation.begins_with("drawing-bow-"):
|
||||
DrawingBowAnimationFinished.emit()
|
||||
@@ -47,18 +21,8 @@ func OnAnimationFinished() -> void:
|
||||
|
||||
func PlaySpecifiedAnimation(animation_name: String) -> void:
|
||||
_current_animation = animation_name
|
||||
for part in _all_parts:
|
||||
part.animation = animation_name
|
||||
part.play()
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
_all_parts = [
|
||||
full
|
||||
]
|
||||
|
||||
UpdateSprite()
|
||||
animation = animation_name
|
||||
play()
|
||||
|
||||
|
||||
func _build_animation_name(state: BaseState, direction: Enums.Directions) -> String:
|
||||
@@ -72,7 +36,3 @@ func _direction_to_animation_state(direction: Enums.Directions) -> String:
|
||||
if direction == Enums.Directions.LEFT or direction == Enums.Directions.RIGHT:
|
||||
return "side"
|
||||
return Enums.Directions.keys()[direction].to_lower()
|
||||
|
||||
|
||||
func _should_flip_horizontal() -> bool:
|
||||
return direction_component.GetCurrentDirection() == Enums.Directions.LEFT
|
||||
|
||||
11
Entities/Characters/Player/Scripts/state_event_connector.gd
Normal file
11
Entities/Characters/Player/Scripts/state_event_connector.gd
Normal file
@@ -0,0 +1,11 @@
|
||||
extends Node
|
||||
|
||||
@export var state_machine: PlayerStateMachine
|
||||
|
||||
# Public Methods
|
||||
func OnMovementQueued(direction_vector: Vector2) -> void:
|
||||
state_machine.SendEventToCurrentStateIfValid("MovementQueued", direction_vector)
|
||||
|
||||
|
||||
func OnNoMovementQueued() -> void:
|
||||
state_machine.SendEventToCurrentStateIfValid("NoMovementQueued")
|
||||
@@ -25,6 +25,11 @@ func QueueStateChange(to_state_enum: PlayerStateMachine.States, extra_parameters
|
||||
queued_parameters = extra_parameters
|
||||
|
||||
|
||||
func SendEventToCurrentStateIfValid(signal_name: String, parameters: Variant = null) -> void:
|
||||
if current_state._subscribed_events.has(signal_name):
|
||||
current_state._StateMachine_OnEventSent(signal_name, parameters)
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
var children := states_container.get_children()
|
||||
|
||||
Reference in New Issue
Block a user