How to fix moving diagonally makes player go faster

Consider this code:

# Set initial values
x = 0
y = 0
speed = 1

if right_key_pressed:
    x += speed

if up_key_pressed:
    y -= speed

if down_key_pressed:
    y += speed

if left_key_pressed:
    x -= speed

At first glance, this code seems to be a simple and efficient way to handle player movement in a 2D game. However, there is a problem with this code that causes the player’s movement to be faster when traveling diagonally.

The issue lies in the fact that when the player presses two keys at the same time (e.g. right and up), the player’s position will be updated by the sum of the two movement speeds. This means that the player will move faster diagonally than when moving in a single direction since 1+1 = 2.

To understand why this happens, first let’s understand what we’re trying to do. Think about a 2d grid. When we’re moving, we always want our distance from initial position (assume it’s 0,0) and new position to equal to our speed (in the above diagram one is the speed).

Instead of representing movement as X and Y position increments, take a look at them as angles, as follows:

The definition of a circle is as follows:

a round plane figure whose boundary (the circumference) consists of points equidistant from a fixed point (the center).

This means we can visualize our movement as moving across the boundary (circumference of a circle)! Let’s convert our arrow keys to angles, and use trignometric functions to define our movement vectors.

Arrow Key Pressed Angle (degrees) Sin Value Cos Value
Up 90 1 0
Down 270 -1 0
Left 180 0 -1
Right 0 0 1
Top + Right 45 1/√2 1/√2

This tells us:

Horizontal component = speed * cos(angle)
Vertical component = speed * sin(angle)

Here’s an updated version of the code that takes this into account:

# Set initial values
x = 0
y = 0
speed = 1

# Calculate horizontal and vertical components of movement speed
cos_angle = speed * cos(angle)
sin_angle = speed * sin(angle)

# Update player position
if right_key_pressed:
    x += cos_angle
    y += sin_angle

if up_key_pressed:
    x -= sin_angle
    y -= cos_angle

if down_key_pressed:
    x += sin_angle
    y += cos_angle

if left_key_pressed:
    x -= cos_angle
    y -= sin_angle

With this updated code, the player’s movement will be correctly updated based on the direction of movement, and the issue of faster diagonal movement will be resolved.

Here’s a table comparing the movement of the current code and the expected movement:

Direction Incorrect Code Expected Movement
Right x += speed x += cos(angle)
Up y -= speed y -= sin(angle)
Down y += speed y += sin(angle)
Left x -= speed x -= cos(angle)
Diagonal x += speed, y += speed x += cos(angle), y += sin(angle)

We can also calculate using the formula for a diagonal that our initial buggy code would’ve been off by a factor of sqrt(2) or approximately 41% faster. Using angles fixes it!

I hope this was easy to understand, let me know if you have any questions in the comments!

5 Likes

This is really helpful! Thanks!

1 Like

When your not old enough to understand it all

The graph actually helps ngl, i finally understood smth :sweat_smile:

I smell high school math Im not that high yet

Right, some trig

Question. How could this apply to 3d?

1 Like

Tan? Sin²?

There’s other math ways to do this but a most common one is atan2

I can help you get higher :smirk:

1 Like