How To Do 2D Top-Down Movement – Unity C#

So you want to make a top-down game, but you’re not sure how to handle character movement. I’ll assume you’re a beginner and explain how in detail.

The Code

First, attach a Rigidbody2D component to your 2D character, and turn the gravity scale down to 0. Next, make a new script and attach it to the character and add the following code inside your class (note there is an improved version at the end of this tutorial so if you’re just copy and pasting, scroll down first – although I strongly suggest you read the article to understand what it does):

Rigidbody2D body;

float horizontal;
float vertical;

public float runSpeed = 20.0f;

void Start ()
{
   body = GetComponent<Rigidbody>(); 
}

void Update ()
{
   horizontal = Input.GetAxisRaw("Horizontal");
   vertical = Input.GetAxisRaw("Vertical"); 
}

private void FixedUpdate()
{  
   body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}

Rigidbody

The Rigidbody2D is what handles collisions and physics for 2D characters. We get the component in Start to access the velocity later.

Taking Input

horizontal and vertical will track which keys are being pressed on the keyboard, or what direction you’re pressing the control stick in. For keyboard controls, Input.GetAxisRaw(“Horizontal”) will give us a value of either -1 or 1. Left arrow is -1, right arrow is 1. Vertical will be 1 for up and -1 for down. This should also work for the WASD keys by default without changing any code.

If you’re using a control stick, instead of being either -1 or 1, you will get decimal values between that range depending on the direction of the stick.

Update And Fixed Update

We check the input in Update because Update runs constantly, every frame, so that way we make sure that Unity registers the key was pressed.

Physics tasks, like changing velocity, should be done in Fixed Update, because it’s designed to calculate physics – but it also doesn’t run every frame, so if you put key presses in Fixed Update, sometimes it won’t register that you pressed a key.

Velocity

Velocity is both a speed and a direction (this web page explains that in detail, but I give the simple version below). It is also a property of Rigidbody2D. When we set it to something other than 0, our character will start moving in a direction.

horizontal and vertical determine our direction, being either -1 or 1. Then when we multiply it by the runSpeed to determine how fast we move in the given direction.

When you multiply horizontal with runSpeed, the characters X velocity will be will either be -20 or 20, in other words, they will be moving 20 pixels per second, which would move us right, or -20 pixels per second, which would move us left.

This is how we determine if the character is moving left or right, because negative values will move you left – or down. (You don’t necessarily move in pixels per second but that idea should help you understand).

Using Velocity

Let’s look again at FixedUpdate.

private void FixedUpdate()
{  
   body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}

Here we change the velocity value of our Rigidbody2D. A 2D velocity looks like this:

velocity( X , Y )

Whatever value we put as X, is how fast our character will travel along the X axis; how fast he will travel left or right. If the value is 1, he will travel 1 pixel per second to the right. If the value is 10, he will travel 10 pixels to the right. If the value is -10, he will travel 10 pixels to the left.

The value we put as Y will determine how fast our character will move up and down along the Y axis. 1 would move 1 pixel per second up, -10 would move 10 pixels per second down.

If we rewrote our line of code as the following:

private void FixedUpdate()
{ 
   body.velocity = new Vector2(20, -20);
}

What that would do is make our character move at 20 pixels per second to the right and 20 pixels per second down, every time physics get updated. But we don’t want our character to constantly move in one direction. We want the direction to change when we press keys. So that’s why we have horizontal and vertical to work out which direction we want to go.

Take the following maths:

horizontal = 1;
runSpeed = 20;

newSpeed = horizontal * runSpeed;

If you look at the value of horizontal and runSpeed, newSpeed is clearly 20. And if we changed horizontal to -1, newSpeed would end up being -20.

So look at our code again:

private void FixedUpdate()
{ 
   body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}

body.velocity is a Vector2 because it holds an X and a Y value, the speed and direction we want to move on the X and Y axis. To change it, we have to declare that we want to make a new Vector2, and inside the ( ) parentheses, or brackets, we put the values we want for our X and Y speed, in other words:

private void FixedUpdate()
{ 
   body.velocity = new Vector2( X , Y );
}

A Vector2 quite simply is just a variable that stores 2 numbers, separated by a comma. This is why it is useful to use them to describe 2D velocity, because our velocity has both an X and a Y value.

So if horizontal is 1, we’ll move right, or -1, we’ll move left. Then we multiply it by runSpeed to work out how fast we are moving to the right.

We do the same with vertical – vertical determines up or down, then we multiply it by runSpeed to work out how fast we should move up or down.

You can also do 3D velocity. It looks like this:

velocity ( X , Y, Z )

It works the same way, except that we can now move in 3 dimensions, with the Z direction and speed worked out in the third value.

Too Fast Diagonally

If you haven’t already, test your code. You should see that your character moves, but feels like he moves too fast diagonally if you are using a keyboard. There’s a nice, simple way to fix this.

Create a new variable called moveLimiter at the top of your script with the other variables.

Rigidbody2D body;

float horizontal;
float vertical;
float moveLimiter = 0.7f;

public float runSpeed = 20.0f;

The part in blue is the new code.

Forgetting all of the mathematical reasons why, for diagonal movement to feel right, you want to move 70% slower than we currently do when we move diagonally. That’s what moveLimiter is for, because mutliplying a number by 0.7 gives us 70% of that number.

Let’s add some new code to FixedUpdate – add the parts in blue:

private void FixedUpdate()
{
   if (horizontal != 0 && vertical != 0) // Check for diagonal movement
   {
      // limit movement speed diagonally, so you move at 70% speed
      horizontal *= moveLimiter;
      vertical *= moveLimiter;
   }

   body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}

So we added a new if statement. Our if statement checks if you’re moving diagonally – if horizontal and vertical are both not equal to 0, you’re moving diagonally.

moveLimiter has the value of 0.7. So when we multiply any number by 0.7, that will give us 70% of that number.

Ironically in this case, multiplying horizontal by 0.7 will make horizontal equal to 0.7 or -0.7, but if we just said:

horizontal = 0.7f;

It would always be positive, so you could only ever move right. But if horizontal is -1, and we multiply that by 0.7, we’ll end up with -0.7, so we can move at 70% speed to the left. This is why we use a combination of horizontal and moveLimiter.

Then, when we modify our velocity, the new velocity will be 70% slower because we have modified the values of horizontal and vertical to be 70% of their value, so we will be multiplying our runSpeed value by either 0.7 or -0.7, again, setting out speed to 70% of runSpeed.

Keyboard Or Controller

This scheme is intended for keyboard. For controllers, you don’t need to limit the movement speed because when you press diagonal on a controller it does that automatically.

So if you plan to make your game work with both keyboards and controllers, check which input is being used and modify your code accordingly – don’t check for diagonal movement with controllers.

Final Code

As promised, here is the final version of the code:

Rigidbody2D body;

float horizontal;
float vertical;
float moveLimiter = 0.7f;

public float runSpeed = 20.0f;

void Start ()
{
   body = GetComponent<Rigidbody2D>();
}

void Update()
{
   // Gives a value between -1 and 1
   horizontal = Input.GetAxisRaw("Horizontal"); // -1 is left
   vertical = Input.GetAxisRaw("Vertical"); // -1 is down
}

void FixedUpdate()
{
   if (horizontal != 0 && vertical != 0) // Check for diagonal movement
   {
      // limit movement speed diagonally, so you move at 70% speed
      horizontal *= moveLimiter;
      vertical *= moveLimiter;
   } 

   body.velocity = new Vector2(horizontal * runSpeed, vertical * runSpeed);
}

Conclusion

So you’ve got your character moving and you hopefully understand why it moves.  In a future tutorial I might go over how to also make your character face a different direction based upon the direction you’re moving.

I also made a puzzle game called The Nodus. Check it out.

Follow this blog for more game development tutorials and info about my upcoming games.

 

 

10 thoughts on “How To Do 2D Top-Down Movement – Unity C#

    • Did you try using WASD? If you used the method I mentioned, it should work already. Unity’s in-built Input.GetRawAxis / “horizontal” / “vertical” accounts for both arrows and WASD.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s