How can I stop the player movement from being too fast while moving diagonally in my 2D game?

In my 2D project the player movement is too fast when moving diagonally, however when moving along a single axis it is fine. The player movement is done using a rigid-body if that makes any difference. It is also a top-down styled game.


In my understanding this is a fairly common problem with movement in 2D games. I’ve heard it has something to do with numbers being added together when there is more than one input, there by doubling the speed when the player is moving in a diagonal direction. A fix i have heard about it something along the lines of; if the movement equals greater than 1, divide it by 2 so that it is equal to 1 again. It sort of computes in my brain yet I have no idea how to implement this in unity.


Here’s the code:

    public Rigidbody2D rb;
    private Vector2 movement;
    private float moveSpeed = 5f;
    
    void Update()
    {
            movement.x = Input.GetAxisRaw("Horizontal");
            movement.y = Input.GetAxisRaw("Vertical");
    }
    
    private Void FixedUpdate()
    {
            rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
    }

I’m just not sure how to code in the if statement that halves the speed, or if it is even possible with this movement setup. If someone could even just let me know if I’m going down the right path here that would be great. Maybe there is a simpler solution to this problem I haven’t heard of? Any help is appreciated.


Thank you :slight_smile:

You’re right that when moving in multiple directions the vectors of your movement are added. If you’re moving up one unit per second and to the right one unit per second you’re actually traveling at a combined speed of the square root of 2 (about 1.41). To fix this, we can make sure that your “Vector2 movement” is locked to a certain value. This way if a player is moving in multiple directions at once, their speed will never exceed the same speed they would have moving in a single direction.

Here’s how you can do this in your code:

void Update()
{
        movement.x = Input.GetAxis("Horizontal");
        movement.y = Input.GetAxis("Vertical");

        movement = Vector2.ClampMagnitude(movement, 1);
}

This will “Clamp” or limit the size of your movement vector to one meaning the player will always move at the same speed (unless they are affected by gravity or some other force of course).

This is a cool question to explore.

It’s actually a problem in 3D space as well, if you’re using a combination of input vectors to move your character.

The problem is:

So a Vector has a magnitude (how much you move) and direction (where you move). When you combine two vectors with the same magnitude but different directions, you’ll either end up with a bigger vector (like in this case) or a smaller one.

You want your vector’s magnitude to stay the same, like this:

The quickest fix, if you don’t wanna do the math manually, is to normalize your resulting vector and then multiply it by speed, deltaTime etc. When you normalize a vector its direction stays the same but the magnitude is changed to 1.

So:

void Update()
     {
             movement.x = Input.GetAxisRaw("Horizontal");
             movement.y = Input.GetAxisRaw("Vertical");
     }
     
     private Void FixedUpdate()
     {
             Vector2 direction = movement.normalized;
             rb.MovePosition(rb.position + direction * moveSpeed * Time.fixedDeltaTime);
     }

This will however only work with a 0 or 1 input, anything in between will turn to 1.
If you plan on having input that isn’t like a key press (0 or 1), you’ll need to do the math.

Which in your case (Since the angle between the vectors is always 90 deg) will be dividing the resulting vector’s magnitude by the square root of 2.