Rotating in 2-D

Every spinning thing in a game — a turret tracking the player, a coin twirling on a table, a twin-stick ship facing its aim — is, at heart, the same little piece of trigonometry. Before we touch three dimensions, quaternions, or any of the exotic machinery, we build the one matrix that turns the plane about the origin by an angle \theta. Everything else in this chapter grows from it.

We already met this matrix in pure form on rotation matrices; here we re-derive it from scratch, with a game designer leaning over our shoulder.

Where do the basis vectors land?

A linear map is completely pinned down by what it does to the two basis vectors \hat{\imath} = (1,0) and \hat{\jmath} = (0,1): once you know their images, every other vector is just a combination of them. So rotating the plane reduces to one question — where do these two arrows go?

Step 1 — rotate \hat{\imath} = (1,0). It starts on the positive x-axis with length 1. Swing it anticlockwise by \theta and its tip rides the unit circle to the point at angle \theta:

\hat{\imath} \;\longmapsto\; (\cos\theta,\; \sin\theta).

Step 2 — rotate \hat{\jmath} = (0,1). It starts pointing straight up, at angle 90^\circ. Adding \theta puts it at angle 90^\circ + \theta, and \cos(90^\circ + \theta) = -\sin\theta, \sin(90^\circ + \theta) = \cos\theta:

\hat{\jmath} \;\longmapsto\; (-\sin\theta,\; \cos\theta).

Step 3 — stack the images as columns. The columns of a transformation matrix are the images of the basis vectors. Drop them in, in order:

R(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}.

That is the whole 2-D rotation matrix, conjured by asking two arrows where they were going.

Apply it to a point

Step 4 — multiply R(\theta) by a point (x, y). A matrix times a vector is just a weighted sum of the columns:

R(\theta)\begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}\begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} x\cos\theta - y\sin\theta \\ x\sin\theta + y\cos\theta \end{bmatrix}.

Step 5 — sanity-check with a quarter turn. Set \theta = 90^\circ, so \cos\theta = 0 and \sin\theta = 1. The point (x, y) maps to (-y, x) — the player at (3, 0) swings up to (0, 3), exactly the anticlockwise quarter-turn you'd expect.

Two rotations add their angles

Rotate by \beta, then by \alpha. The combined motion ought to be a single rotation by \alpha + \beta — and the matrices say so. Multiply R(\alpha)R(\beta) out.

Step 6 — multiply the two matrices.

R(\alpha)R(\beta) = \begin{bmatrix} \cos\alpha & -\sin\alpha \\ \sin\alpha & \cos\alpha \end{bmatrix}\begin{bmatrix} \cos\beta & -\sin\beta \\ \sin\beta & \cos\beta \end{bmatrix}.

Step 7 — expand each entry (row times column):

= \begin{bmatrix} \cos\alpha\cos\beta - \sin\alpha\sin\beta & -(\cos\alpha\sin\beta + \sin\alpha\cos\beta) \\ \sin\alpha\cos\beta + \cos\alpha\sin\beta & \cos\alpha\cos\beta - \sin\alpha\sin\beta \end{bmatrix}.

Step 8 — recognise the angle-sum identities. Each entry is exactly a \cos or \sin of \alpha + \beta:

R(\alpha)R(\beta) = \begin{bmatrix} \cos(\alpha+\beta) & -\sin(\alpha+\beta) \\ \sin(\alpha+\beta) & \cos(\alpha+\beta) \end{bmatrix} = R(\alpha + \beta).

Composing rotations adds their angles — and since addition commutes, in the plane the order never matters (R(\alpha)R(\beta) = R(\beta)R(\alpha)). Enjoy that while it lasts; in three dimensions it is the first thing to break.

The anticlockwise rotation of the plane about the origin by an angle \theta is the linear map with matrix

R(\theta) spins about the origin, but a game rarely wants that — a door swings about its hinge, a planet orbits its sun, a sprite spins about its own centre \mathbf{p}, not about (0,0). The fix is the classic translate, rotate, translate back sandwich. To rotate a point \mathbf{v} about the pivot \mathbf{p}:

\mathbf{v}' = R(\theta)\,(\mathbf{v} - \mathbf{p}) + \mathbf{p}.

Subtracting \mathbf{p} slides the pivot to the origin, where R(\theta) knows how to work; adding it back afterwards puts the world where it belongs. This bracketing trick — move the problem to where the maths is easy, solve it, move it back — returns again and again, and it is exactly how composing transformations chains pivots, scales and spins together.

Turn the dial

The blue arrow is a fixed point P = (x, y). The orange arrow is its image R(\theta)\,P. Drag the angle slider: the point rides a circle of fixed radius about the origin, its length never changing, while the live matrix and rotated coordinates update beneath it. At \theta = 90^\circ watch (x, y) jump to (-y, x).