ATAN2 is one of those quiet little functions that suddenly solves problems I’d been writing tricky code for. At its core it returns the angle between two points and handles the quadrant for you, which ATN(dy/dx) doesn’t.
The basic call:
angle = ATAN2(dy, dx)
angle comes back in radians, which is exactly what most follow-up operations want. If you need degrees, pipe it through DEG(). Three places where it really paid off for me.
A direction vector between two points
When you want one object to fly toward another, the recipe is almost always the same: take the difference vector, derive the angle, turn it back into a velocity vector.
dx = target_x - src_x
dy = target_y - src_y
angle = ATAN2(dy, dx)
vx = COS(angle) * speed
vy = SIN(angle) * speed
Sounds like a detour, but it’s useful because you can mess with the angle before turning it back into components. Which is what I need next.
Rotate by ±90° to get an orthogonal vector
When two objects collide and something is supposed to peel off sideways, I don’t want two random directions, I want directions perpendicular to the impact axis. With ATAN2 that’s one line plus a +90° and a -90°:
parent_angle = ATAN2(parent_vy, parent_vx)
angle_a = parent_angle + RAD(90)
angle_b = parent_angle - RAD(90)
Then turn each back into velocity components. You get physically plausible splittings for fragments, reflections, or “spawn left and right of the motion vector” effects. Without ATAN2 you’d write out the rotation matrix by hand, which works but reads worse.
Aiming with random spread
For an enemy AI tracking the player, I don’t want perfect aim. A bit of spread per shot keeps the enemy fair and gives the gameplay some texture. ATAN2 plus a random offset on the angle is again a tight little expression:
dx = player_x - enemy_x
dy = player_y - enemy_y
angle = ATAN2(dy, dx) + (RND() - 0.5) * spread
shot_vx = COS(angle) * shot_speed
shot_vy = SIN(angle) * shot_speed
spread is how wide the angular noise is, in radians. Vary it by enemy type or difficulty level and you’ve got a tuning knob with zero extra cost.
What ties these three patterns together: one ATAN2 call, then operate on the angle, then back to components with COS and SIN. The math is trivial, and the code reads like you actually meant it. That’s why ATAN2 ended up high in my mental toolbox.