Case Study 2.1 — Vectors That Move: Displacement and Velocity in a Game Engine
Field: computer science / game development. Ties to: the chapter's displacement reading of vectors (§2.2, §2.10) and the magnitude formula (§2.5). Every position, velocity, and force in a game is a vector, and the engine combines them with the two operations you just learned.
The setting
Open almost any game and you are watching vector arithmetic run sixty times a second. A character standing at a spot on the map has a position vector. When it moves, its new position is the old position plus a displacement vector. When something shoves it — an explosion, a sword hit, a gust of wind — the engine adds an impulse vector to its velocity. When you watch a fireball arc across the screen, you are seeing a velocity vector get nudged by a gravity vector every frame. The "game feel" that players describe as weighty, floaty, snappy, or sluggish is, underneath, choices about how vectors are scaled and added.
In this case study we trace one short sequence of motion for a single character and show that everything the engine needs — where the character ends up, how far it traveled, how fast it's going after a hit — comes out of vector addition, scalar multiplication, and magnitude. No new mathematics; just the chapter's tools applied to a problem a game studio actually solves.
Walking the character
Our character starts at position $\mathbf{p}_0 = \begin{bmatrix} 2 \\ 1 \end{bmatrix}$ (in tile coordinates: 2 east, 1 north of the map origin). Over three frames the player issues three moves, each a displacement vector:
$$ \mathbf{m}_1 = \begin{bmatrix} 3 \\ 0 \end{bmatrix} \ (\text{run east}), \quad \mathbf{m}_2 = \begin{bmatrix} 0 \\ 4 \end{bmatrix} \ (\text{run north}), \quad \mathbf{m}_3 = \begin{bmatrix} -1 \\ -1 \end{bmatrix} \ (\text{step southwest}). $$
The engine updates the position one frame at a time, each update a single vector addition:
$$ \mathbf{p}_1 = \mathbf{p}_0 + \mathbf{m}_1 = \begin{bmatrix} 5 \\ 1 \end{bmatrix}, \quad \mathbf{p}_2 = \mathbf{p}_1 + \mathbf{m}_2 = \begin{bmatrix} 5 \\ 5 \end{bmatrix}, \quad \mathbf{p}_3 = \mathbf{p}_2 + \mathbf{m}_3 = \begin{bmatrix} 4 \\ 4 \end{bmatrix}. $$
The character ends at $(4, 4)$. Now two natural questions a designer asks. First, what is the net displacement — the single arrow from start to finish? That is the final position minus the initial position (subtraction as "from here to there," §2.2):
$$ \Delta \mathbf{p} = \mathbf{p}_3 - \mathbf{p}_0 = \begin{bmatrix} 4 \\ 4 \end{bmatrix} - \begin{bmatrix} 2 \\ 1 \end{bmatrix} = \begin{bmatrix} 2 \\ 3 \end{bmatrix}. $$
Notice the net displacement $\begin{bmatrix} 2 \\ 3 \end{bmatrix}$ is exactly the sum of the three moves $\mathbf{m}_1 + \mathbf{m}_2 + \mathbf{m}_3$ — tip-to-tail composition says the order and the intermediate stops don't change the net arrow. That is the parallelogram rule generalized to three legs.
Second, how far did the character actually walk versus how far it ended up from the start? The path length is the sum of the lengths of the three moves, while the straight-line distance is the magnitude of the net displacement:
$$ \text{path} = \lVert \mathbf{m}_1\rVert + \lVert \mathbf{m}_2\rVert + \lVert \mathbf{m}_3\rVert = 3 + 4 + \sqrt{2} \approx 8.41, $$ $$ \text{straight-line} = \lVert \Delta\mathbf{p}\rVert = \sqrt{2^2 + 3^2} = \sqrt{13} \approx 3.61. $$
The character walked 8.41 tiles but ended up only 3.61 tiles from where it started — exactly the difference between "distance traveled" and "displacement" that the chapter's two readings of subtraction make precise.
# A game character's path: positions update by vector addition each frame.
import numpy as np
p0 = np.array([2.0, 1.0])
moves = [np.array([3.0, 0.0]), np.array([0.0, 4.0]), np.array([-1.0, -1.0])]
pos = p0.copy()
for m in moves:
pos = pos + m # one frame of motion = one vector add
print("final position:", pos) # [4. 4.]
net = pos - p0
print("net displacement:", net) # [2. 3.]
print("straight-line distance:", np.linalg.norm(net)) # 3.605551275463989
print("path length:", sum(np.linalg.norm(m) for m in moves)) # 8.414213562373096
The printed values — final position [4. 4.], net displacement [2. 3.], straight-line distance 3.6055..., path length 8.4142... — match the hand computation exactly.
Getting hit: adding an impulse to velocity
Movement is only half the story; physics is the other half. Suppose the character is running east with velocity $\mathbf{v} = \begin{bmatrix} 5 \\ 0 \end{bmatrix}$ (tiles per second) when an explosion to the southwest delivers an impulse $\mathbf{j} = \begin{bmatrix} -2 \\ 3 \end{bmatrix}$ — a sudden change in velocity. The new velocity is, once again, a vector sum:
$$ \mathbf{v}' = \mathbf{v} + \mathbf{j} = \begin{bmatrix} 3 \\ 3 \end{bmatrix}, \qquad \lVert \mathbf{v}' \rVert = \sqrt{3^2 + 3^2} = \sqrt{18} \approx 4.24 \text{ tiles/s}. $$
The hit slows the character down (speed drops from 5 to about 4.24) and redirects it to the northeast. A designer tuning the "knockback" of a weapon is choosing the impulse vector $\mathbf{j}$; a bigger $\mathbf{j}$ (scale it up — scalar multiplication) means a harder hit. Damping — the gradual slowing of a sliding object — is scalar multiplication by a factor slightly less than 1 each frame, say $\mathbf{v} \leftarrow 0.9\,\mathbf{v}$, which shrinks the velocity vector toward zero without changing its direction (until other forces act). Every one of these is an operation from this chapter.
# A hit adds an impulse to velocity; damping scales it down.
import numpy as np
v = np.array([5.0, 0.0])
impulse = np.array([-2.0, 3.0])
v_new = v + impulse
print("velocity after hit:", v_new) # [3. 3.]
print("speed after hit:", np.linalg.norm(v_new)) # 4.242640687119285
print("after one frame of 0.9x damping:", 0.9 * v_new) # [2.7 2.7]
The velocity after the hit [3. 3.], the speed 4.2426..., and the damped velocity [2.7 2.7] all match the hand result, and the damped vector points in the same direction (northeast) but is shorter — the geometric signature of scalar multiplication by a positive number less than 1.
Why this matters
Three lessons generalize far beyond games. First, sequential motion is repeated vector addition; the net effect is a single sum, independent of how you got there — the tip-to-tail principle. Second, "how far traveled" (sum of leg lengths) and "how far displaced" (magnitude of the net vector) are genuinely different quantities, and the chapter's subtraction-as-displacement reading is what separates them. Third, the feel of an interactive system is engineered by choosing scalars and impulse vectors — game design is, in a real sense, applied linear algebra at the level of this chapter.
Scaling up: a modern game holds thousands of moving entities, each a small bundle of vectors, and the engine updates them all by adding and scaling vectors in tight loops on the GPU — hardware built, fundamentally, to add and scale vectors in parallel by the million. The two operations you learned to do by hand on a $2$-vector are the same two operations a graphics card performs billions of times per second. When we reach Chapter 7 and matrices enter, those same entities will also be rotated and scaled non-uniformly by matrices — but the positions and velocities they move along will still be the vectors of this chapter. To see the 2D arrows of this case study drawn on real axes with matplotlib, the companion treatment in plotting vectors is a natural next step.