✚ Game development

Simple game physics: gravity, velocity and a good jump

Gravity, velocity and acceleration in a 2D game: semi-implicit Euler integration, a jump tuned by height and duration, friction and speed limits.

You do not need a full physics engine to make a character move well. In most 2D action games three quantities are enough, position, velocity and acceleration, updated with a few lines of code. The hard part is not the maths but the tuning: a «right» jump is a design choice before it is a physics one.

Position, velocity, acceleration

The relationship between these quantities is simple:

  • velocity says how much the position changes every second;
  • acceleration says how much the velocity changes every second.

Gravity is a constant downward acceleration. On each update, with a time step dt, you apply two operations:

velocity.y += gravity * dt
position.y += velocity.y * dt

The order matters. Updating velocity first and then position with the new velocity is called semi-implicit (or symplectic) Euler, and it is more stable than the «naive» version that uses the old velocity. For games it is the standard method: simple, cheap and accurate enough if the step is fixed and small.

In screen coordinates the y axis usually grows downwards, so gravity is positive and a jump has a negative initial velocity. This is a frequent source of confusion when moving from one engine to another.

Designing the jump from the result

Picking random values for gravity and jump strength leads to long trial-and-error sessions. It is more effective to start from two parameters a game designer can understand:

  • the maximum height of the jump, in pixels or tiles;
  • the time to reach the apex, in seconds.

From the laws of uniformly accelerated motion you derive the physical quantities directly:

gravity = 2 * height / (time_to_apex * time_to_apex)
jump_velocity = -2 * height / time_to_apex

For example, a 96-pixel jump that reaches its apex in 0.4 seconds requires a gravity of 1,200 pixels per second squared and an initial velocity of −480 pixels per second. If you then want a higher jump, you change only the height and recompute the rest, keeping the same sense of duration.

Making the jump feel good

A physically realistic jump, with a perfectly symmetrical parabola, often feels «floaty». Some widely used tricks in platformers:

Stronger gravity on the way down

Applying stronger gravity when the character is falling, for example 1.5 or 2 times the rising gravity, makes the fall more decisive and the control more responsive.

Variable height

Players expect a short press to produce a low jump and a long press a high one. The simplest way: if the button is released while the character is still rising, reduce the vertical velocity, for example by halving it. Alternatively, increase gravity while the button is not held.

Maximum fall speed

Without a cap, a long fall drives the character to enormous speeds, which make precise landings hard and can cause it to pass through thin platforms. A cap on vertical speed, often called terminal velocity, solves both problems.

Horizontal movement: acceleration and friction

Sideways movement also benefits from acceleration rather than an instant snap:

if right pressed:
    velocity.x += acceleration * dt
else if left pressed:
    velocity.x -= acceleration * dt
else:
    velocity.x = move_toward_zero(velocity.x, friction * dt)

velocity.x = clamp(velocity.x, -max_speed, max_speed)

The move_toward_zero function reduces the absolute value without going past zero, preventing the character from jittering back and forth as it stops. Different acceleration and friction values produce very different feels:

Acceleration Friction Feel
High High Precise control, instant response
Low Low Slippery movement, like on ice
High Low Quick start, long stop
Low High Heavy character, slow start

It also helps to reduce air control compared with ground control: a character that changes direction mid-air as readily as on the floor is not very believable, but removing it entirely makes the game frustrating. An intermediate value is almost always the best compromise.

Other useful forces

The same scheme extends easily:

  • wind or currents: a constant horizontal acceleration in one area of the level;
  • bounce: after hitting the ground, reverse the vertical velocity and multiply it by a coefficient less than 1;
  • enemy knockback: add an instant impulse to the velocity, an immediate change rather than an acceleration over time;
  • water: reduced gravity and increased friction in both directions.

Make everything tweakable

The most practical advice is to expose every parameter in a configuration file or a debug panel that can be edited while the game is running. In my work I have seen that the difference between mediocre and enjoyable movement almost always lies in small adjustments made while playing, not in the formulas. Recompiling every time a number changes slows this process down enormously.

In short

  • Position, velocity and acceleration are enough for convincing game physics.
  • Semi-implicit Euler integration with a fixed step is stable and simple.
  • Gravity and jump velocity follow from the desired height and the time to apex.
  • Stronger falling gravity, variable jumps and a speed cap improve the feel.
  • Horizontal acceleration and friction define the character of the movement.
MM
Marco Marzaduri

Marco Marzaduri works in cybersecurity, digital forensics and web development. A computer science graduate, he combines rigorous technical analysis with attention to the people who use technology.

Read also