- 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
71 lines
1.8 KiB
GDScript
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")
|