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. This tutorial assumes you have some familiarity with programming and Unity, but are needing a bit more help. With that in mind, I’ll explain how to do this 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.

Troubleshooting Errors

If for some reason you are having errors or the code doesn’t seem to be working, here are some practical steps for you to follow to try and solve what’s wrong (and then I’ll explain in more detail below about each step and how to go about it):

  1. Know your skill level – this tutorial is not for people who don’t know any programming, it assumes at least some prior knowledge
  2. Read the tutorial (the whole thing) slowly and carefully
  3. Read back over your code carefully and slowly to make sure it’s the same as the tutorial – it’s easy to miss typos
  4. If there is an error message, copy and paste the message into Google – someone likely had the issue before
  5. If there is an error message, double click the error and it will take you to the section of your code which has the error – look at it carefully for clues
  6. Use break points to debug (if you know how)
  7. Go to Unity Answers to ask about your problem – you’ll get a quick answer
  8. Otherwise, leave a comment here and I’ll get back to you as soon as possible, but Unity Answers will give you a quicker response time and is a useful resource

Know Your Skill Level

This tutorial assumes that you have at least some experience with Unity and Programming, but that you need a bit of extra help. I don’t go into the absolute basics of explaining things like what are variables, what is a class, where to type your code, etc.

For that, you need to go to either Youtube or Udemy and look up some beginner programming courses in C#, then come back here when you’re ready. And I also suggest the official Unity tutorials.

Eventually I’ll be doing beginner programming tutorials.

Read The Tutorial Carefully

I know some people like to skim tutorials. You’re doing yourself a disadvantage, because if you’re here, it’s because you don’t understand. Take the time to read the tutorial carefully, don’t rush it, and my explanations should help you to get better understanding.

Read The Code Carefully

This is a big one and sometimes I think one of the key differences between a good programmer and a great one. Whenever I code, I take my time writing it, and I read it over slowly and carefully. I believe this is the main reason I rarely get errors.

If you read code too quickly, you can think you’re reading something that’s not there. Our mind fills in blanks. That’s why it is so important to not rush when writing or reading code!

As an extra measure, if you’re copying code from somewhere else, make sure you read that slowly and carefully too – one little typo and BOOM! Error. But that’s coding.

Use Break Points To Debug

This is a whole subject in itself, but debugging is a way to read more about what is happening at a particular point in time in your code.

Here’s the Microsoft tutorial on using the debugger for Visual Studio.

Search Google

I was once told a story about a programmer applying for a job. He asked, “What skill do you most value in a programmer?” The response was, “Good Google skills.”

It’s true. Any time I have a programming issue, I can almost always find the answer just by searching for it. If I can’t, I can Google for a website where I can ask for the answer, like Unity Answers.

If you get an error message, many times just copy and pasting the actual error message into Google will get you the result you need.

Double Click The Error Message

Assuming there is an error message (the other type of error is when your program behaves unexpectedly, and there is no error message), double click on it. Unity will send you to the line of code where it thinks the error lies.

This will not always solve your problem, but it can help. Sometimes the line of code it shows you is not actually where the problem is. When doing this, I always try to:

  1. Double click on the top error message first (as fixing this can sometimes fix other errors)
  2. Look at the 3 lines of code immediately above where Unity thinks the error is in my code, because sometimes that’s where the actual problem is

If your error is because of a typo, Unity can get very confused about which line is the problem. In this case, it is often the line above what Unity thinks. If there are lots of typos because you’re a beginner, well, then you’re going to have a much trickier time just reading through the code and may need extra help. Try Unity Answers.

Unity Answers

Unity Answers is fantastic! You won’t always get an answer to your question, but usually I’ll have a response in under 24 hours. That’s incredible! There’s a whole community of people on there that just like being helpful. So if you have a problem, make sure you go and ask it there if you can’t find the solution through Google searching.

Ask Me

I’m very busy making games, and there’s only one of me, so I can’t reply quickly. Because of this, Unity Answers really is your best resource for help. But feel free to ask for help here too and I will try and get back to you.

23 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

    • In future when you get an error, you should try copy and pasting the error message into google and see if someone else has had it before – they usually have. If not, someone on Unity answers will often be able to get back to you fairly quickly if you can provide them with a sample of code. Without a sample of code it is hard to know where you have gone wrong. It sounds like, however, you have mistyped something and not too familiar with programming, in which case you should be looking at the Unity ‘Learn’ tutorials to get a bit of an idea how to learn Unity, although that won’t properly teach you programming. Look at Udemy also for a course on programming, or find a highly rated Youtube tutorial series.

      Unity official tutorials: https://unity3d.com/learn

      Eventually I will have beginner programming courses but that’s not what this article is.

      Like

    • If you double click the error, it should highlight the section of code. It would be helpful if you could attach that.

      It sounds like you have incorrectly declared the ‘Rigidbody2D’ variable, put some code in the wrong place or mistyped something. Read my code sample again very closely and make sure.

      A useful tip when you get an error is to copy and paste the error message into google – it’s quite common for someone else to have had the error before. I did that and got this, which suggests a mistype: https://answers.unity.com/questions/766896/unexpected-symbol-rigidbody2d.html

      It’s also important to note all of that code as to go inside the scripts “class”. If you’re not sure what that is, and you are a complete beginner programmer, this might not be the best place for you to start. I suggest going through Unity’s official tutorials, starting with the rolling ball tutorial. I will have a beginner programmer course in the coming future, however this is intended for people who are somewhat familiar with programming and some small familiarity with Unity, but have not made a top down game before.

      Like

  1. Love it!

    But is there anyway to move like that but with blocky movement? Like, no slowing down or speeding up, the player just… moved?

    Like

    • There are lots of different ways to do movement. Are you asking about grid based movement, where you move one grid space at a time, or like the old Pokemon games on Gameboy, or simply movement without acceleration?

      Like

    • Not sure which part of the code you’re referring to?

      In any case, the article was long enough and I don’t want to introduce too many new concepts, otherwise it’s something else I would have to explain. Better to get people understanding how to write code, and the basic maths and principles behind it, and then worry about optimizations later.

      Like

    • A good question, but no. When applying forces with RigidBodies in Unity, it automatically calculates delta time for you. My understanding is when manipulating the velocity of the rigidbody directly, the same applies.

      However, if you were creating your own physics system from scratch, yes you would have to factor in delta time manually, to make sure that the physics behaved the same on every PC

      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