Learning

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.

The whole definition

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
eighth 45° π/4
quarter 90° π/2
half 180° π
three-quarter 270° 3π/2
full 360°

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.

Where this bites

Raylib's drawing calls take degreesDrawTextureEx(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:

The green segment is cos θ — how far right the point sits. The orange segment is sin θ — how far up. Together they are the point, and because the radius is 1, they are also a direction of length 1. Tick screen space to see what happens when y grows downward, as it does in raylib and LÖVE.

Three things worth noticing while you drag:

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.

y-down

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.

A ship faces angle θ. Which pair gives its forward direction?
How many radians is a quarter turn?
Your code computes cos θ = 1.35. What has gone wrong?

Do this before the next lesson

Fifteen minutes in a project you already have open — LÖVE or raylib, whichever is faster to start:

  1. Draw a ring of 8 circles around the centre of the screen using i * 2π/8.
  2. Add a slowly increasing t and offset every angle by it, so the ring rotates.
  3. 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.