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!

4 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