Trigonometry for Games and Graphics · Lesson 01 · 20 min
Turning an Angle Into a Direction
Convert any angle into a movement vector with cos and sin, and place objects anywhere on a circle.
A ship points somewhere and thrusts forward. A moon circles a planet. Twelve runes hover in a ring around a character. A shotgun fires five pellets in a fan.
Those look like four problems. They are one problem, asked four times:
I have an angle. I need a direction.
This lesson closes that gap. By the end you will be able to turn any angle into a movement vector, and place any number of objects evenly around a circle — the two operations underneath almost every piece of circular motion you will ever write.
Radians: the unit your code already uses
You know angles in degrees: 90 for a quarter turn, 360 for a full one. Degrees are arbitrary — 360 is a Babylonian accident, convenient because it divides nicely.
Every sin and cos function in every language you use takes radians instead.
A radian is defined by the circle itself: walk along the rim a distance equal to
the radius, and the angle you swept is one radian.
One radian is the angle whose arc length equals the radius. Since a full circle's rim is 2πr long, a full turn is 2π radians ≈ 6.283. That is where the π comes from — it is not decoration, it is the circumference showing up.
So the landmarks you know in degrees have radian twins:
| Turn | Degrees | Radians |
|---|---|---|
| none | 0° | 0 |
| eighth | 45° | π/4 |
| quarter | 90° | π/2 |
| half | 180° | π |
| three-quarter | 270° | 3π/2 |
| full | 360° | 2π |
And to convert, you scale by the ratio between a full turn in each unit:
// Odin
radians := degrees * math.PI / 180.0
degrees := radians * 180.0 / math.PI
Learn to think in radians rather than converting in your head. π/2 should feel like “a quarter turn” the way 90° does. Two useful anchors: 1 radian ≈ 57.3°, and π ≈ 3.14 means half a turn is a bit over three radians.
Raylib's drawing calls take degrees — DrawTextureEx(tex, pos, rotation, …)
wants 45, not π/4 — while math.sin and math.cos take radians.
LÖVE is the opposite: love.graphics.rotate takes radians. A sprite spinning
57× too fast (or 57× too slow) is almost always this bug.
The unit circle is a lookup table for directions
Draw a circle of radius 1 at the origin. Start at the right-hand point, (1, 0), and
sweep counterclockwise by an angle θ. You land on some point.
That point is (cos θ, sin θ).
That is the entire definition. Cosine hands you the x-coordinate, sine hands you the y — of the point you reach after turning by θ. Not a ratio to memorise, not a triangle to label: a position on a circle.
Play with it. Drag the point, or step through the landmark angles, and watch the two numbers change:
Three things worth noticing while you drag:
- Both values live in [−1, 1]. They never escape, because the point never leaves a
circle of radius 1. Any formula of yours that produces
cos θ = 1.4has a bug upstream. - They trade off. At 0° cosine is all the way out at 1 and sine is 0; by 90° they have swapped. Cosine leads, sine follows a quarter turn behind.
- cos²θ + sin²θ = 1, always. That is just Pythagoras on the circle: x² + y² = r², and r is 1. Check a few angles on the dial — the squares always sum to one.
Before reading on: what are cos(π) and sin(π)? Answer out loud, then check.
π is a half turn, which lands you on the far left of the circle at (−1, 0).
So cos π = −1 and sin π = 0. If you reached for a calculator, set the dial to π and watch
the point walk there — the picture is what you want to remember, not the pair of numbers.
The payoff: angle → movement
Because that point is one unit from the origin, (cos θ, sin θ) is a unit vector —
a pure direction, carrying no speed of its own. Multiply it by however fast you want to go:
// Odin + raylib: move a ship forward along its own facing.
forward := rl.Vector2{ math.cos(ship.angle), math.sin(ship.angle) }
ship.position += forward * ship.speed * dt
The same two lines, in Lua:
-- LÖVE: identical idea, y still grows downward on screen.
local fx, fy = math.cos(ship.angle), math.sin(ship.angle)
ship.x = ship.x + fx * ship.speed * dt
ship.y = ship.y + fy * ship.speed * dt
Separating direction from speed is the habit to build. Direction comes from the angle; speed is a scalar you multiply in afterwards. Keeping them apart is what stops diagonal movement from being mysteriously faster than straight movement.
Maths puts +y up; almost every 2D screen puts +y down. Nothing in the formula changes —
(cos θ, sin θ) is still correct — but on screen, increasing θ now sweeps
clockwise. If your turret turns the wrong way, you have found this, not a bug in
your trigonometry. Toggle screen space on the dial above to see the flip.
Placing things around a circle
Orbit a point instead of the origin by adding the centre back on, and scale by the radius you want instead of 1:
x = centre_x + math.cos(angle) * radius
y = centre_y + math.sin(angle) * radius
That is the whole formula for orbits, radial menus, and rings of enemies. To space n
things evenly, hand each one an equal slice of the full turn:
for i = 0, n - 1 do
local angle = i * (2 * math.pi) / n
local x = centre_x + math.cos(angle) * radius
local y = centre_y + math.sin(angle) * radius
spawn(x, y)
end
Divide 2π by the count, multiply by the index. A ring of 12 runes is i * 2π/12. A fan of
5 shotgun pellets is the same trick over a narrower spread instead of a full turn.
Check yourself
Answer from memory before scrolling back up. Getting one wrong and then seeing why is worth more than getting it right from the text still on screen.
Do this before the next lesson
Fifteen minutes in a project you already have open — LÖVE or raylib, whichever is faster to start:
- Draw a ring of 8 circles around the centre of the screen using
i * 2π/8. - Add a slowly increasing
tand offset every angle by it, so the ring rotates. - Multiply the radius by
1 + 0.2 * sin(t)so the ring also breathes in and out.
Step three is a preview of the next idea: sine is not only a coordinate, it is also the
most useful oscillator you have. Notice that you did nothing new to get it — the same
sin call, read a different way.
Go deeper
Primary source: Trigonometry • Math for Game Devs by Freya Holmér. Watch the opening sections on angles, radians, and the unit circle, then stop — the rest of the lecture is the next few lessons. It is the best-matched resource for this course — a working game developer teaching exactly these ideas with live visuals.
If you want the same material in text, the 3D Math Primer covers it in Angles, Degrees, and Radians and Trig Functions.
Keep the unit circle reference open while you code, and the
glossary for the vocabulary. The full list of vetted sources is
in RESOURCES.md at the root of this course.
Next
Lesson two inverts today’s move. You can now go from an angle to a point — but a turret
that tracks the player needs the opposite: from a point back to an angle. That is atan2,
and it has exactly one trap in it worth knowing about in advance.
Anything above unclear, or did the practice task fight you? Ask — I’m your teacher for this course, and a confusion caught now is worth three lessons later.