Skip to content

Air control tuning three models

const AIR_ACCELERATION_HYBRID = 750.0   // ~half of ground ACCELERATION
const AIR_FRICTION_HYBRID     = 400.0   // notably lower than ground FRICTION
const AIR_NUDGE_ACCEL         = 200.0   // committed model: tiny corrective force only

state launch_velocity_x = 0.0   // captured once per jump, used by the committed model

// --- Model A: full control -------------------------------------------------
function apply_air_control_full(dt):
    // Identical math to grounded movement — no penalty for being airborne.
    apply_horizontal_acceleration(dt)

// --- Model B: committed to the arc ------------------------------------------
function on_leave_ground():
    launch_velocity_x = velocity.x   // snapshot at the moment of takeoff

function apply_air_control_committed(dt):
    input_dir = get_input_direction()
    // Velocity is locked to what it was at launch, plus at most a small nudge.
    // The player aims with their pre-jump run-up, not with mid-air steering.
    velocity.x = move_toward(velocity.x, launch_velocity_x + input_dir * 40.0,
                              AIR_NUDGE_ACCEL * dt)

// --- Model C: hybrid (reduced air accel/friction) ---------------------------
function apply_air_control_hybrid(dt):
    input_dir = get_input_direction()
    target_speed = input_dir * MAX_SPEED
    rate = AIR_ACCELERATION_HYBRID if input_dir != 0 else AIR_FRICTION_HYBRID
    velocity.x = move_toward(velocity.x, target_speed, rate * dt)

function update(dt):
    if not is_grounded and was_grounded_last_frame:
        on_leave_ground()

    if AIR_CONTROL_MODE == "full":
        apply_air_control_full(dt)
    elif AIR_CONTROL_MODE == "committed":
        apply_air_control_committed(dt)
    else:
        apply_air_control_hybrid(dt)

How it works

All three models reuse the same underlying Move Toward-based acceleration structure from section 1 — the difference is entirely in the constants and what the "target" is, which is exactly why it's worth presenting them side by side rather than as unrelated systems.

Full control (AIR_ACCELERATION_HYBRID == ground values, effectively) treats the air identically to the ground. It's the most forgiving and responsive — mistakes are correctable mid-air — but it also makes jump arcs feel weightless, since there's no real difference between "on the ground" and "airborne" from a control standpoint. Good fit for fast, mistake-tolerant arcade platformers (Super Meat Boy leans this direction).

Committed to the arc snapshots horizontal velocity the instant the character leaves the ground (on_leave_ground) and only allows a small nudge on top of it thereafter. The player's real steering input was everything they did before jumping — their run-up speed and direction — and the jump itself plays out largely as a ballistic arc once airborne. This rewards precise positioning and timing before a jump and makes jumps feel physically weighty and consequence-laden (classic Prince of Persia, some Trine sections), at the cost of being unforgiving of a jump thrown at a bad angle.

Hybrid is what most modern platformers actually ship (Celeste, Mario). It keeps the same accel/friction model as the ground but with meaningfully lower constants — momentum from before the jump carries over and dominates, but the player retains real, felt steering rather than losing it entirely. This is generally the best starting point unless you have a specific reason to reach for one of the extremes; it also composes cleanly with wall-jump lockout (section 4), since lockout is just "hybrid air control temporarily set to zero-influence."