The fundamental building block for programming motion — an entity with magnitude and direction.
Imagine you're programming a bouncing ball. You need to track where it is and how fast it's moving. In the simplest approach, you'd write something like this:
pseudocode x = 100 y = 100 xspeed = 1 yspeed = 3.3 each frame: x = x + xspeed y = y + yspeed
That works. But now imagine you want to add acceleration, wind, friction, a target location. Suddenly you need xacceleration, yacceleration, xwind, ywind, xfriction, yfriction… Two variables for every concept. In 3D, you'd need three.
x and y for location and xspeed and yspeed for velocity, you have location and velocity — each a vector. Cleaner code, and a rich set of mathematical operations comes for free.This chapter introduces vectors from scratch. We'll learn what they are, how to add, subtract, multiply, and normalize them, and then use them to drive motion on screen. Every single example in the rest of this book depends on vectors.
| Without vectors | With vectors |
|---|---|
| x, y, xspeed, yspeed, xaccel, yaccel | location, velocity, acceleration |
| 6 separate variables | 3 vector objects |
| Manual per-component math | Built-in operations (add, mult, mag, etc.) |
A Euclidean vector is an entity with two properties: magnitude (how long it is) and direction (which way it points). We draw it as an arrow.
Think of it as an instruction: "Walk 3 steps east, then 4 steps north." That instruction has a direction (northeast-ish) and a magnitude (5 steps total, by the Pythagorean theorem). The instruction doesn't care where you start — it only describes a displacement.
In code, a 2D vector is simply two numbers: an x component and a y component.
pseudocode class Vector: x # horizontal component y # vertical component
Location? A vector: (x, y). Velocity? A vector: (xspeed, yspeed). Acceleration? A vector: (xaccel, yaccel). Same data structure, different meaning. The power comes from the operations we can perform on them.
| Concept | As a vector | Meaning |
|---|---|---|
| Location | (200, 150) | 200px right, 150px down from origin |
| Velocity | (3, -1) | Moving 3px right and 1px up per frame |
| Acceleration | (0, 0.1) | Speeding up by 0.1px/frame downward |
The most fundamental vector operation is addition. If velocity tells you "how much to move per frame," then updating your location is just adding the velocity vector to the location vector:
Mechanically, we add component-by-component:
For example: location (5, 3) + velocity (2, -1) = new location (7, 2). The object moved 2 pixels right and 1 pixel up.
pseudocode function add(v): x = x + v.x y = y + v.y
This single operation — adding velocity to location — is the engine behind every moving object in this entire book. Forces will change velocity (Chapter 2), and velocity will change location. It's vectors all the way down.
If addition answers "where will I end up?", subtraction answers "how do I get from here to there?" Subtracting one vector from another gives us the vector between them:
Example: target is at (300, 200), I'm at (100, 150). The vector from me to the target is (300 − 100, 200 − 150) = (200, 50). That tells me: go 200 pixels right and 50 pixels down.
Geometrically, A − B is the vector from B's tip to A's tip (when both are drawn from the origin). Or equivalently, A + (−B): flip B around and add it tip-to-tail.
Time to see vectors in action. Below you can drag two vector endpoints and watch addition and subtraction in real time. The orange arrow is vector A, the teal arrow is vector B, and the purple arrow shows their sum (A + B) using the tip-to-tail method.
Drag the orange and teal arrowheads. The purple arrow shows A + B. The dotted arrow shows A − B. Components shown numerically below.
We can scale a vector by multiplying it by a scalar (a single number). This changes the magnitude without changing the direction:
Multiply by 2: the vector is twice as long, same direction. Multiply by 0.5: half as long. Multiply by −1: same length, opposite direction.
| Operation | Example: v = (3, 4) | Result |
|---|---|---|
| v × 2 | (3×2, 4×2) | (6, 8) |
| v × 0.5 | (3×0.5, 4×0.5) | (1.5, 2) |
| v × −1 | (3×−1, 4×−1) | (−3, −4) |
| v / 5 | (3/5, 4/5) | (0.6, 0.8) |
Scalar multiplication is essential for controlling speed. Want your object to move twice as fast? Multiply its velocity by 2. Want to slow it down by half? Multiply by 0.5. Want to reverse direction? Multiply by −1.
How long is a vector? Its magnitude (or length) is computed using the Pythagorean theorem. For a vector (x, y):
Example: the vector (3, 4) has magnitude √(9 + 16) = √25 = 5. If this were a velocity, the object moves 5 pixels per frame. The direction is "3 right, 4 down" but the speed is 5.
In code, we compute magnitude and sometimes use magnitude squared (magSq = x*x + y*y) to avoid the expensive square root when we only need to compare magnitudes (e.g., "is this object within 100 pixels?" becomes "is magSq < 10000?").
pseudocode function magnitude(): return sqrt(x * x + y * y) function magnitudeSquared(): return x * x + y * y
To normalize a vector means to make its magnitude equal to 1, while keeping the same direction. The result is called a unit vector.
Take vector (3, 4) with magnitude 5. Divide each component by 5: (3/5, 4/5) = (0.6, 0.8). Check: √(0.36 + 0.64) = √1 = 1. The direction is preserved but the length is now exactly 1.
direction = target - location; direction.normalize(); direction.mult(maxSpeed);This is exactly how Shiffman implements the "mouse follower" example. The object computes a vector pointing from itself to the mouse, normalizes it (to get the direction), and then multiplies by a desired speed. Without normalization, the object would teleport to the mouse instead of gliding toward it.
pseudocode function normalize(): m = magnitude() if m > 0: x = x / m y = y / m
Everything we've learned comes together here. Motion in this book follows a simple chain:
This two-line update is the heartbeat of every simulation in the book. In the demo below, the ball accelerates toward your mouse (or toward a draggable target on touch devices). The acceleration vector is computed using subtraction and normalization:
pseudocode dir = target - location # vector pointing to target dir.normalize() # make it unit length dir.mult(0.5) # scale to desired accel acceleration = dir
Move your mouse (or drag on touch) to set the target. The ball accelerates toward it. Watch velocity accumulate — the ball overshoots and orbits because there's no friction.
Vectors are the foundation for everything that follows. Here's what we've built:
| Operation | What it does | Used for |
|---|---|---|
| add(v) | Component-wise addition | Applying velocity to location |
| sub(v) | Component-wise subtraction | Finding direction to target |
| mult(n) | Scale by a number | Controlling speed |
| div(n) | Scale by 1/n | Dividing force by mass (F = ma) |
| mag() | Pythagorean length | Measuring speed, distance |
| normalize() | Make unit length | Getting pure direction |
velocity += acceleration; location += velocity; — two lines that power every bouncing ball, every particle, every autonomous agent in this book. Acceleration is where the "nature" enters. Gravity, wind, steering — they all produce an acceleration vector.What we covered:
• Vectors as (x, y) pairs
• Addition (tip-to-tail)
• Subtraction (direction between points)
• Scalar multiplication/division
• Magnitude (Pythagorean)
• Normalization (unit vectors)
• Location/velocity/acceleration
What comes next:
Chapter 2: Forces. We learn that acceleration doesn't just appear — it comes from forces. Newton's second law (F = ma) tells us force = mass × acceleration. We'll apply gravity, wind, friction, and drag to our vector-based movers.