◀ 1.31.41.5 ▶

1.4 — Movement I: Input, Direction, Vector

Movement looks effortless in a game. In code it is an algorithm: read the player's input → turn it into a distance → move the character. Every line is given below.

Starting point: Assets/Scripts/PlayerController.cs is a shell — two empty methods. The Player has a Transform and nothing else: no physics, no collider.

In this lesson you will be able to answer“how do I move an object in Unity?”Full walkthrough
Break It Down~10 minFull walkthrough

Move the character when I press the arrow keys. As one problem, that is far too big to start typing.

First, before any code: cut that into parts small enough that you could look each one up on its own.

  1. Find out which way the player is pushingAsk the keyboard for two numbers, one per axis, each between -1 and 1, and keep them in fields so they survive the frame.Read: The axis reads in the quick reference, and 1.3's declare-vs-assign rule.
  2. Turn those two numbers into one directionA pair of numbers is awkward to move by. Combine them into one Vector2: a single value meaning "this far, in this direction".Read: Vector2 in the quick reference.
  3. Scale that direction by speed and by the frameMultiply by moveSpeed to turn a direction into a distance, and by Time.deltaTime so the distance is per second rather than per frame.Read: The deltaTime row in the quick reference.
  4. Move the player by that distance, every frameHand the finished offset to the Player's own Transform, which adds it to where the Player already is.Read: transform.Translate(v) in the quick reference.

Four parts, and only one is the part you would have thought of first. "Move the player" sounds like one action; it is a read, a build, a scale and an offset.

The test for a finished split: could you look this part up on its own, in one search? "Move the player" cannot; "get keyboard input as a number" can.

Your turn

Read the input, build a direction, apply the movement. Which of those three would still work unchanged if you swapped the keyboard for a gamepad stick — and why is that a sign the split is a good one?

In the Editor~12 min
  1. Project window → Assets/Scripts, double-click PlayerController.cs to open it.
  2. Hierarchy → select the Player, then Inspector → read the Player Controller (Script) component: two methods, nothing to tune yet.
  3. Game view → press Play and hold WASD. Nothing moves — the shell runs and does nothing.
  4. Edit → Project Settings → Input Manager: read the Horizontal and Vertical axes. Neither is a single key, and a gamepad stick is already in the list.
  5. Game view → press Play once your script is written and hold WASD. The character glides in all four directions.
  6. Inspector → while the game runs, change the Move Speed box. Then GitHub Desktop → commit and push your movement code.
In the Code~20 min

Four ways to ask Unity for movement. You write the first and the last today; the middle two are here because choosing between them is a design decision.

Unity APIReturnsBehaviour
Input.GetAxis("Horizontal")float (−1.0 to 1.0)Smooth ramp. Accelerates to −1 or +1 and coasts back to 0, so movement has a little weight.
Input.GetAxisRaw("Horizontal")float (−1, 0 or 1)Instant snap. Exactly −1, 0 or 1 the moment a key changes, so it stops on a dime.
Input.GetKey(KeyCode.D)boolBinary state. True while the physical D key is held — that key only.
transform.Translate(vector)voidOffsets the position by a vector — a relative step: "move this far from where I am."

Socratic: Evaluating Multiple Ways to Solve a Problem

  1. A driving game wants weight and momentum: Input.GetAxis("Horizontal") or Input.GetAxisRaw("Horizontal")? Why?
  2. A grid puzzle where you must stop on a dime: why would Input.GetAxisRaw("Horizontal") be the better choice?
  3. A player wants the arrow keys instead of WASD. Why is the axis "Horizontal" more flexible than Input.GetKey(KeyCode.D)?
In the CodeFull walkthrough

The question this answers“how do I move an object in Unity?”

You are editing Assets/Scripts/PlayerController.cs. Type these into the class body, in this order.

Step 1Open the class and add the speed knob

PlayerController is already on the Player with two empty methods. It needs one number first: how fast to move.

// PlayerController.cs — the whole file. Add the field inside the class.
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 5f;
  1. 6Units travelled per second. [SerializeField] puts it in the Inspector, so it can be tuned while the game runs.

Step 2Declare the fields that remember the input

These two go in the class body, next to the speed knob.

// PlayerController.cs — still the class body, below the speed knob.
    private float inputX;
    private float inputY;

    void Update()
    {
  1. 2Left/right as a number: -1, 0 or 1. In the class body it belongs to the Player, not to the frame.
  2. 3The same for up/down: -1, 0, or 1.
  3. 5The method Unity calls every frame.

Step 3Read the keyboard

Ask Unity what is being pressed right now, and store it in the two fields you just declared.

        inputX = Input.GetAxis("Horizontal");
        inputY = Input.GetAxis("Vertical");

        Vector2 movement = new Vector2(
            inputX * moveSpeed * Time.deltaTime,
            inputY * moveSpeed * Time.deltaTime);
  1. 1Reads the virtual axis "Horizontal" into inputX. There is no float in front of it — the variable exists, so this line assigns.Write float inputX = ... here and you shadow the field with a temporary variable that dies with the frame. Most students hit this bug.
  2. 2The same read for up/down. Spell it exactly "Vertical": capitals matter.
  3. 4Builds the direction. This one is declared here: it is used two lines later, and nothing next frame needs it.
  4. 5Horizontal distance this frame: direction × speed × frame time.
  5. 6The same for vertical. The closing ); finishes the Vector2.

Step 4Apply the movement

You hold a displacement — "move this far from where I am." Hand it to the Transform.

        transform.Translate(movement);
    }
  1. 1Offsets the Player's position by that displacement. Every GameObject already has a transform.
Check your work: the finished filebuild it as you read — then open this to check every line

Compare it against your own file: inputX and inputY declared in the class body and only assigned inside Update(), and every displacement line scaled by the frame time.

// ------------------------------------------------------------------
//  REFERENCE FILE — Assets/Scripts/PlayerController.cs
//  Written to be read, not pasted. Build it with the walkthrough
//  above, one step at a time, then open this and compare.
//  If it is sitting in your project unchanged, that is the thing
//  to go and do now — the walkthrough is still above you.
// ------------------------------------------------------------------
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 5f;

    private float inputX;
    private float inputY;

    void Update()
    {
        inputX = Input.GetAxis("Horizontal");
        inputY = Input.GetAxis("Vertical");

        float stepThisFrame = moveSpeed * Time.deltaTime;
        Vector2 movement = new Vector2(inputX, inputY) * stepThisFrame;

        transform.Translate(movement);
    }
}
Bug Hunt~20 min

Your character glides in all four directions. Now prove you know why.

Bug Hunt: Testing Assumptions

  1. Delete the per-frame multiplier from both displacement lines. Tap a direction key: why does the character cross the whole map in one frame?
  2. Set the Move Speed box to 0 while the game runs, then to 30. Describe the difference.
  3. Swap the two numbers you pass into the direction — vertical where the horizontal belongs. What does the character do now, and why?
  4. Move the declaration: cut private float inputX; from the class body and declare float inputX inside Update(), on the line where the read happens. Does the character still move? Explain with declare and assign.
  5. Walk your character into a wall and keep pushing. What happens? Look back at the component list from 1.2: what is the Player missing?
Keep that last answer. Walking through walls is not a mistake in your code: transform.Translate(vector) edits coordinates directly, so nothing ever told it a wall was there.

Checkpoint — before moving on, you must be able to:

Reference Docs

Need a deeper explanation? These pages cover the same concepts:

Next: 1.5 — Movement II: Speed, deltaTime & Tuning, where you compare four ways to move an object and pick the one this game needs.

0/8 answered

Answers save on this device as you type. At the end of class, click Download and upload the file to the Canvas assignment.

Saved on this device only — the Dashboard tracks your progress.