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")