Speed and gravity

This page describes how to implement basic physics in sidescroller games (running around, jumping, etc.). This should help you make your game have decent controls and in many cases may be more than enough. You should be able to also apply similar concepts in other situations.

Note: this page doesn't talk about collision (that's a whole topic that deserves a page on its own and depends on the particular game), only speed physics.

Subpixels

First of all: using pixels for position is a bad idea. Think about it: if the slowest speed you can store is 1px, then that'll be 60px per second (since you add it every frame). You can't do slower than that, and the next step is 120px per second. That's way too much.

Instead we must use a smaller unit (a "subpixel"), or in other words, make it so that 1px is a large number, e.g. 65536 (a power of two). Then if e.g. we want to move 0.75px per frame (45px per second), we could store it as 0.75 × 65536 = 49152. This is called "fixed point".

To show something on screen, we divide the number by a pixel, but we keep the whole number while doing physics. Division on the 68000 is slow, so make sure to use a power of two (then you can use bit shifting, which is much faster!).

Iwis says

You may want to look at our page on fixed point to get a better idea of what we're talking about as well as some hints on how to do this in an optimal way.

Iwis says

If you're using SGDK, it already comes with fixed point stuff. Look at the fix32 type and relevant functions like fix32Add (add two fix32 values) and fix32Int (get the integer part out of a fix32).

X and Y speeds

There are two speed values you should need:

They should be self-explanatory. The "speed" is pretty much how many pixels an object moves every frame. You should keep track of the speed of every object across frames, so store it as part of their current state.

Every frame, after you've done all speed calculations (what we're going to see after this), you can apply the result by simply adding the speed to the current position:

x = x + x_speed
y = y + y_speed

Running around

The simple choice to make a character walk or run is to set the horizontal speed (X speed) to how fast they should move, but that doesn't feel natural. Instead, you should accelerate the speed, i.e. make the speed increase over a few frames.

Acceleration is simply incrementing speed every frame:

x_speed = x_speed + acceleration

However, you don't want to keep going faster non-stop! You want to impose a limit on how fast you go (known as the "speed cap"). So if we cross the speed cap, we prevent the speed from going beyond that. Note that if we were already going faster we do nothing at all (to prevent awkward situations).

The reason for checking whether acceleration is positive or negative is to cope with the fact that the limit needs to match, nothing more.

if acceleration == 0
   do nothing

else if acceleration > 0 and x_speed < limit
   x_speed = x_speed + acceleration
   if x_speed > limit then x_speed = limit

else if acceleration < 0 and x_speed > -limit
   x_speed = x_speed + acceleration
   if x_speed < -limit then x_speed = -limit
end

Stop running

When we release the left/right button we want to decelerate, i.e. start slowing down. Deceleration is decrementing the speed every frame. We check that it doesn't cross 0 (since it may not land exactly on it), but it's otherwise similar to what we did above.

if x_speed == 0
   do nothing

else if x_speed > 0
   x_speed = x_speed - deceleration
   if x_speed < 0 then x_speed = 0

else if x_speed < 0
   x_speed = x_speed - deceleration
   if x_speed > 0 then x_speed = 0
end

Running into a wall

When moving around you may run into a wall and will need to react to it. Just set horizontal speed to 0 to stop.

Jump and fall

Besides horizontal speed (X speed), there's also vertical speed (Y speed). Gravity is accelerating the vertical speed every frame (e.g. increase it 0.25px every frame). When you hit the floor, the vertical speed is reset back to 0, so that next time you fall you will start by falling slowly again.

y_speed = y_speed + gravity

Jumping is pretty much setting the vertical speed to a large negative number, e.g. -7px per frame. So, if the jump button is pressed and you're on the floor, change the vertical speed then let gravity do its job (and make sure to make a "boing" noise!).

if jump_button and on_floor
   y_speed = -jump_speed
   play_sfx jump
end

Friction while in the air

If something feels off, that's because while you're in the air it should be harder to change your horizontal speed! To fix this, we can make both acceleration and deceleration to be half as strong while we're in the air (do this before doing the speed calculations):

if not on_floor
   acceleration = acceleration >> 1
   deceleration = deceleration >> 1
end

Variable jump height

In many genres it's common to be able to jump higher or lower depending how "hard" (how long) you press the jump button. There are several approaches to this, I'm going to focus on the Project MD approach since it's simple.

The idea is: if you're moving upwards and you aren't holding down the jump button, then you fall faster. Which means that applying gravity now should look more like this:

y_speed = y_speed + gravity
if y_speed < 0 and (not jump_button)
   y_speed = y_speed + extra_gravity
end

Useful numbers

Here are some numbers that have served me well from experience, mainly intended for the kind of platformers you normally see on 4th generation consoles. You should tweak these depending on your needs (try them, play, then change anything that feels off).

If you're making a game more like Sonic (where the emphasis is on slowly gaining and keeping momentum), then something like this may fit better: