Files
Papay-Shooter/movement/states/state_air.gd
T
Hermes 202f67fa32 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
2026-06-02 22:36:00 -04:00

71 lines
1.8 KiB
GDScript

extends Node
class_name StateAir
var machine: MovementStateMachine
var params: MovementParams:
get: return machine.params
func enter(_data: Dictionary = {}) -> void:
pass
func exit() -> void:
pass
func update(delta: float) -> void:
var vel: Vector3 = machine.player.velocity
# Apply standard gravity
vel.y -= params.gravity * delta
# Input direction
var input_v := machine.input_dir
var wish_dir := Vector3(input_v.x, 0.0, -input_v.y)
if wish_dir.length_squared() > 1.0:
wish_dir = wish_dir.normalized()
var effective_speed := machine.get_effective_speed(params.max_air_speed)
var hvel := Vector3(vel.x, 0.0, vel.z)
var target_vel := wish_dir * effective_speed * params.air_control
hvel = hvel.lerp(Vector3(hvel.x + target_vel.x, 0.0, hvel.z + target_vel.z), 1.0 - exp(-params.air_acceleration * delta))
vel.x = hvel.x
vel.z = hvel.z
# Bunny hop: if jump pressed and on ground near-peak of arc → extra boost
if machine.input_jump_just_pressed and machine.on_ground:
vel.y = params.jump_velocity * params.bunny_hop_impulse
machine.player.velocity = vel
machine.register_chain_mechanic("bunny_hop")
machine.current_jump_count += 1
machine.on_ground = false
machine.switch_to("air")
return
# Double Jump
if machine.input_jump_just_pressed and not machine.on_ground and machine.current_jump_count < params.double_jump_max_count:
vel.y = params.double_jump_velocity
machine.player.velocity = vel
machine.current_jump_count += 1
machine.register_chain_mechanic("double_jump")
machine.switch_to("air")
return
machine.player.velocity = vel
machine.player.move_and_slide()
# Landing
if machine.player.is_on_floor():
machine.on_ground = true
machine.current_jump_count = 0
machine.switch_to("ground")
return
# Wall run transition
if not machine.wall_normal.is_zero_approx():
machine.switch_to("wall_run")