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.
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.
- 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.
- 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:Vector2in the quick reference. - Scale that direction by speed and by the frameMultiply by
moveSpeedto turn a direction into a distance, and byTime.deltaTimeso the distance is per second rather than per frame.Read: ThedeltaTimerow in the quick reference. - 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?
- Project window →
Assets/Scripts, double-clickPlayerController.csto open it. - Hierarchy → select the Player, then Inspector → read the Player Controller (Script) component: two methods, nothing to tune yet.
- Game view → press Play and hold WASD. Nothing moves — the shell runs and does nothing.
- 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.
- Game view → press Play once your script is written and hold WASD. The character glides in all four directions.
- Inspector → while the game runs, change the Move Speed box. Then GitHub Desktop → commit and push your movement code.
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 API | Returns | Behaviour |
|---|---|---|
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) | bool | Binary state. True while the physical D key is held — that key only. |
transform.Translate(vector) | void | Offsets the position by a vector — a relative step: "move this far from where I am." |
Socratic: Evaluating Multiple Ways to Solve a Problem
- A driving game wants weight and momentum:
Input.GetAxis("Horizontal")orInput.GetAxisRaw("Horizontal")? Why? - A grid puzzle where you must stop on a dime: why would
Input.GetAxisRaw("Horizontal")be the better choice? - A player wants the arrow keys instead of WASD. Why is the axis
"Horizontal"more flexible thanInput.GetKey(KeyCode.D)?
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;- 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()
{- 2Left/right as a number:
-1,0or1. In the class body it belongs to the Player, not to the frame. - 3The same for up/down:
-1,0, or1. - 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);- 1Reads the virtual axis
"Horizontal"intoinputX. There is nofloatin front of it — the variable exists, so this line assigns.Writefloat inputX = ...here and you shadow the field with a temporary variable that dies with the frame. Most students hit this bug. - 2The same read for up/down. Spell it exactly
"Vertical": capitals matter. - 4Builds the direction. This one is declared here: it is used two lines later, and nothing next frame needs it.
- 5Horizontal distance this frame: direction × speed × frame time.
- 6The same for vertical. The closing
);finishes theVector2.
Step 4Apply the movement
You hold a displacement — "move this far from where I am." Hand it to the Transform.
transform.Translate(movement);
}- 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);
}
}Your character glides in all four directions. Now prove you know why.
Bug Hunt: Testing Assumptions
- Delete the per-frame multiplier from both displacement lines. Tap a direction key: why does the character cross the whole map in one frame?
- Set the Move Speed box to
0while the game runs, then to30. Describe the difference. - Swap the two numbers you pass into the direction — vertical where the horizontal belongs. What does the character do now, and why?
- Move the declaration: cut
private float inputX;from the class body and declarefloat inputXinsideUpdate(), on the line where the read happens. Does the character still move? Explain with declare and assign. - 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?
transform.Translate(vector) edits coordinates directly, so nothing ever told it a wall was there.
Checkpoint — before moving on, you must be able to:
- State the sub-problems of movement: input → vector → distance → translation
- Point at your own file and say which lines declare and which lines assign
- Choose between a smooth axis, a raw axis and a single key for a given game
- Explain why movement has to be scaled by how long the frame took
- Tune the speed knob while the game runs
- Explain why your character can walk through a wall
Reference Docs
Need a deeper explanation? These pages cover the same concepts:
- Unit 1: Setup & Movement — input, vectors, and translation in depth
- Unity + C# Quick Reference — input and vector functions
- How do I…? index — find this lesson again by the question you were asking
Next: 1.5 — Movement II: Speed, deltaTime & Tuning, where you compare four ways to move an object and pick the one this game needs.
Saved on this device only — the Dashboard tracks your progress.