feat: implement player movement controller and state machine with dash, slide, and wall-run mechanics
This commit is contained in:
@@ -6,9 +6,22 @@ signal chain_updated(count: int, bonus: float)
|
||||
@export var params: MovementParams = preload("res://movement/movement_params.gd").new()
|
||||
|
||||
var _machine: MovementStateMachine = null
|
||||
var head_pivot: Node3D = null # FPSCameraRig node
|
||||
var camera: Camera3D = null
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var sm := _ensure_machine()
|
||||
if sm:
|
||||
sm.player = self
|
||||
sm.params = params
|
||||
sm.movement_event.connect(_on_movement_event)
|
||||
|
||||
# Find camera rig
|
||||
head_pivot = get_node_or_null("HeadPivot")
|
||||
if head_pivot:
|
||||
camera = head_pivot.get_node_or_null("Camera3D")
|
||||
|
||||
# Explicitly ensure this node ticks after being attached by set_script().
|
||||
func _ensure_process() -> void:
|
||||
set_process(true)
|
||||
set_physics_process(true)
|
||||
|
||||
@@ -25,49 +38,35 @@ func _ensure_machine() -> MovementStateMachine:
|
||||
return null
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var sm := _ensure_machine()
|
||||
if not sm:
|
||||
return
|
||||
|
||||
# Poll input in _physics_process so it's synchronized with the state machine tick
|
||||
sm.input_jump_just_pressed = Input.is_action_just_pressed("jump")
|
||||
sm.input_jump_pressed = Input.is_action_pressed("jump")
|
||||
sm.input_sprint = Input.is_action_pressed("sprint")
|
||||
sm.input_crouch = Input.is_action_pressed("crouch")
|
||||
sm.input_dash = Input.is_action_just_pressed("dash")
|
||||
sm.input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||
|
||||
# Raw 2D input
|
||||
var raw_input := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||
|
||||
func _ready() -> void:
|
||||
var sm := _ensure_machine()
|
||||
if sm:
|
||||
sm.player = self
|
||||
sm.params = params
|
||||
sm.movement_event.connect(_on_movement_event)
|
||||
_ensure_process()
|
||||
# Transform input direction by player yaw so movement is camera-relative
|
||||
var forward := -global_transform.basis.z
|
||||
forward.y = 0.0
|
||||
forward = forward.normalized()
|
||||
var right := global_transform.basis.x
|
||||
right.y = 0.0
|
||||
right = right.normalized()
|
||||
|
||||
var world_dir := (forward * (-raw_input.y) + right * raw_input.x)
|
||||
if world_dir.length_squared() > 1.0:
|
||||
world_dir = world_dir.normalized()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
var sm := _ensure_machine()
|
||||
if not sm:
|
||||
return
|
||||
sm.input_jump_just_pressed = Input.is_action_just_pressed("jump")
|
||||
sm.input_jump_pressed = Input.is_action_pressed("jump")
|
||||
sm.input_sprint = Input.is_action_pressed("sprint")
|
||||
sm.input_crouch = Input.is_action_pressed("crouch")
|
||||
sm.input_dash = Input.is_action_just_pressed("dash")
|
||||
sm.input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||
|
||||
# DEBUG: emit every frame so we can see whether inputs reach the controller.
|
||||
var p = sm.player
|
||||
print("MOVEMENT_DEBUG state=%s vel=%s input_dir=%s jump=%s sprint=%s crouch=%s dash=%s" % [
|
||||
sm.current_state,
|
||||
p.velocity if p else "NO_PLAYER",
|
||||
sm.input_dir,
|
||||
sm.input_jump_pressed,
|
||||
sm.input_sprint,
|
||||
sm.input_crouch,
|
||||
sm.input_dash,
|
||||
])
|
||||
sm.input_dir = raw_input
|
||||
sm.wish_dir_world = world_dir
|
||||
|
||||
|
||||
func _on_movement_event(ev: String, data: Dictionary) -> void:
|
||||
|
||||
Reference in New Issue
Block a user