Key Ideas
1Position & Velocity. pygame.Vector2 stores pos and vel. Every frame: pos += vel * dt, where dt is seconds elapsed since the last frame — keeps speed consistent across machines.
2Acceleration & Friction. ACCEL ramps velocity toward max_speed while a key is held; FRICTION decays velocity back toward zero when there's no input, clamped so it never overshoots past zero.
3Gravity & Jumping. Gravity is a constant added to vel.y every frame. JUMP_FORCE is negative because Pygame's Y axis increases downward — moving up the screen means decreasing y.
4Double Jump. Track a jumps_left counter. Reset it to MAX_JUMPS only when on_ground is true; decrement it each time try_jump() succeeds.
5Dash. A short burst of high velocity in the facing direction for a fixed duration, gated by a cooldown timer so it can't be spammed.
6Screen Boundaries. Clamp pos.x/pos.y to [0, screen_w - width] and [0, screen_h - height] after moving so the player can never leave the play area.
7Smooth & Camera-Relative Movement. Lerp (a + (b-a)*t) eases a value toward a target each frame — used for a follow-camera easing toward the player instead of snapping rigidly.