feat(movement): add movement state machine with air/ground/wallrun/slide/dash/ground states
- MovementStateMachine: core state machine base - MovementParams: export-rich tunable resource - StateGround/StateAir: grounded & aeriel locomotion with coyote, buffered jump, bunny hop - StateWallRun / StateWallCling: wall-based traversal with wall-jump off - StateSlide: sprint-parallel slide with friction fallout - StateDash: burst dash with momentum brake - PlayerMovementController: entry point wiring to CharacterBody3D - input_map.cfg: full action map reference file - characters/player/player_base.tscn: placeholder scene - movement/tests/test_fsm_runner.gd: 9-state unit test runner Closes #1
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
extends CharacterBody3D
|
||||
class_name PlayerMovementController
|
||||
|
||||
## PlayerMovementController — root node for all player 3D locomotion.
|
||||
## Attach to a CharacterBody3D with a CollisionShape3D.
|
||||
## States are expected to be children: state_ground, state_air,
|
||||
## state_wall_run, state_wall_cling, state_slide, state_dash.
|
||||
|
||||
signal chain_updated(count: int, bonus: float)
|
||||
|
||||
@export var params: MovementParams = preload("res://movement/movement_params.gd").new()
|
||||
|
||||
var machine: MovementStateMachine
|
||||
var jump_buffered: bool = false
|
||||
|
||||
# ── Input references ─────────────────────────────────────────────────────────
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("ui_accept"):
|
||||
# Space / jump
|
||||
pass
|
||||
_machine.input_jump_just_pressed = Input.is_action_just_pressed("jump")
|
||||
_machine.input_jump_pressed = Input.is_action_pressed("jump")
|
||||
_machine.input_sprint = Input.is_action_pressed("sprint")
|
||||
_machine.input_crouch = Input.is_action_pressed("crouch")
|
||||
_machine.input_dash = Input.is_action_just_pressed("dash")
|
||||
var input_v := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||
_machine.input_dir = input_v
|
||||
|
||||
|
||||
@onready var _machine: MovementStateMachine = $MovementStateMachine
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_machine.player = self
|
||||
_machine.params = params
|
||||
# Mirror signal up
|
||||
_machine.movement_event.connect(func(ev, data):
|
||||
if ev == "chain_updated":
|
||||
chain_updated.emit(data.count, data.bonus)
|
||||
)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
_machine.input_jump_just_pressed = Input.is_action_just_pressed("jump") and not _machine.input_jump_pressed
|
||||
_machine.input_jump_pressed = Input.is_action_pressed("jump")
|
||||
_machine.input_sprint = Input.is_action_pressed("sprint")
|
||||
_machine.input_crouch = Input.is_action_pressed("crouch")
|
||||
_machine.input_dash = Input.is_action_just_pressed("dash") and not _machine.input_dash
|
||||
var input_v := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||
_machine.input_dir = input_v
|
||||
Reference in New Issue
Block a user