Skip to content

Understanding atan2

Published: at 12:00 AM

Have you ever wanted to make a character face towards the player, a turret track its target, or a missile home in on its destination? The atan2 function is your friend here. Let’s break it down from first principles and build up to practical game development applications.

Trigonometry Refresher

Can you think way back to your high school math classes? One of the topics you might remember is trigonometry, which deals with the relationships between the angles and sides of triangles.

A quick mnemonic to remember the trigonometric functions is SOHCAHTOA:

  • Sine = Opposite / Hypotenuse
  • Cosine = Adjacent / Hypotenuse
  • Tangent = Opposite / Adjacent

As a quick refresher, play around with the interactive demo below to see how the sine, cosine, and tangent functions work:

Opposite (220)Adjacent (320)Hypotenuse (388)θ
sin θ = 0.567
cos θ = 0.824
tan θ = 0.688
Angle θ = 34.5°

What is atan2?

Now that we’ve refreshed our trigonometry basics, let’s dive into atan2.

If you remember, each trigonometric function has an inverse function. An inverse function is like a “reverse” function that undoes the original function.

In this case, the inverse functions of each trig function simply means “given the ratio of the two sides, return the angle of a right triangle satisfying this”. This is usually denoted by adding a small -1 to the function name. For example, the inverse of \sin is \sin^{-1}.

However, this is hard to type out, so some mathematicians like to add an arc prefix instead. So the inverse of \sin is also called \arcsin. This is then abbreviated as asin in many cases.

So, what about atan2? It’s the inverse of the tangent function, but with a twist. Instead of taking a single ratio of sides, it takes two separate values: the y and x coordinates of a point. This makes it more powerful and flexible than the regular atan function.

Let’s recap this real quick. We know that the definition of \tan is:

\tan(\theta) = \frac{\text{opposite}}{\text{adjacent}}

So, the inverse of this function, atan, would take a single ratio and return the angle. In other words:

\text{atan}\left(\frac{\text{opposite}}{\text{adjacent}}\right) = \theta

For convenience, the atan2 function unpacks this for us, taking the y and x coordinates separately:

\text{atan2}(\text{y}, \text{x}) = \text{atan}\left(\frac{\text{y}}{\text{x}}\right) = \theta

atan2 in Action

Let’s see how atan2 works in practice. Imagine you have two points on a 2D plane: a source point and a target point. You want to find the angle between these two points.

You can represent this function as a triangle:

Angle: -26.6°dx: 100.0dy: -50.0

atan2 is a mathematical function that helps us find the angle between two points. While it might sound intimidating, it’s actually quite straightforward once you understand what it does.

Think of it this way: if you have two points on a 2D plane, atan2 tells you what angle you need to rotate to face from one point towards the other.

// Basic atan2 usage
const angle = Math.atan2(targetY - sourceY, targetX - sourceX)

Interactive Demo: Understanding atan2

import { useState } from 'react'

export default function Atan2Demo() {
  const [mousePos, setMousePos] = useState({ x: 200, y: 200 })
  const centerX = 200
  const centerY = 200
  
  const angle = Math.atan2(
    mousePos.y - centerY,
    mousePos.x - centerX
  )
  
  return (
    <div 
      className="relative w-96 h-96 bg-slate-100 rounded-lg"
      onMouseMove={(e) => {
        const rect = e.currentTarget.getBoundingClientRect()
        setMousePos({
          x: e.clientX - rect.left,
          y: e.clientY - rect.top
        })
      }}
    >
      {/* Center point */}
      <div 
        className="absolute w-4 h-4 bg-blue-500 rounded-full"
        style={{
          left: centerX - 8,
          top: centerY - 8
        }}
      />
      
      {/* Rotating arrow */}
      <div
        className="absolute w-20 h-1 bg-red-500 origin-left"
        style={{
          left: centerX,
          top: centerY,
          transform: `rotate(${angle}rad)`
        }}
      />
      
      {/* Angle display */}
      <div className="absolute top-4 left-4 bg-white p-2 rounded shadow">
        Angle: {(angle * 180 / Math.PI).toFixed(1)}°
      </div>
    </div>
  )
}

In this interactive demo, move your mouse around to see how atan2 calculates the angle between the center point and your cursor. The red line will always point towards your mouse cursor.

Why atan2 Instead of Regular arctangent?

You might wonder why we use atan2 instead of just regular arctangent (atan). The key difference is that atan2 takes two parameters (y and x) instead of one (y/x), which gives us two major advantages:

  1. No division by zero: If x is zero, regular arctangent would fail, but atan2 handles this case correctly.
  2. Full angle range: Regular arctangent only gives us angles between -90° and 90°, while atan2 gives us the full 360° range.

Practical Application: Making Objects Face Each Other

Let’s create a practical example where we make a “turret” face towards a moving target.

import { useState, useEffect } from 'react'

export default function TurretDemo() {
  const [targetPos, setTargetPos] = useState({ x: 300, y: 200 })
  const turretPos = { x: 100, y: 200 }
  
  // Animate target in a circle
  useEffect(() => {
    const interval = setInterval(() => {
      const time = Date.now() / 1000
      setTargetPos({
        x: 300 + Math.cos(time) * 50,
        y: 200 + Math.sin(time) * 50
      })
    }, 16)
    return () => clearInterval(interval)
  }, [])
  
  const angle = Math.atan2(
    targetPos.y - turretPos.y,
    targetPos.x - turretPos.x
  )
  
  return (
    <div className="relative w-96 h-96 bg-slate-100 rounded-lg">
      {/* Turret */}
      <div 
        className="absolute w-16 h-16"
        style={{
          left: turretPos.x - 32,
          top: turretPos.y - 32
        }}
      >
        <div className="w-full h-full bg-gray-700 rounded-full" />
        <div 
          className="absolute w-24 h-4 bg-gray-800 origin-left top-6"
          style={{
            transform: `rotate(${angle}rad)`
          }}
        />
      </div>
      
      {/* Target */}
      <div 
        className="absolute w-8 h-8 bg-red-500 rounded-full"
        style={{
          left: targetPos.x - 16,
          top: targetPos.y - 16
        }}
      />
    </div>
  )
}

This demo shows a turret that automatically tracks a moving target. The target moves in a circle, and the turret’s barrel always points towards it using atan2.

Common Gotchas and Tips

  1. Radians vs Degrees: atan2 returns angles in radians. To convert to degrees, multiply by 180/Math.PI.

  2. Coordinate Systems: Remember that most computer graphics use a coordinate system where Y increases downward. This might mean you need to negate your Y values or adjust your angles accordingly.

  3. Performance: While atan2 is generally fast enough for most uses, if you’re calculating it for many objects every frame, consider caching the result if the positions haven’t changed.

Practical Examples

Here are some common use cases for atan2 in game development:

// Making an enemy face the player
function updateEnemyRotation(enemy, player) {
  enemy.rotation = Math.atan2(
    player.y - enemy.y,
    player.x - enemy.x
  )
}

// Calculating direction for projectile motion
function shootProjectile(source, target, speed) {
  const angle = Math.atan2(
    target.y - source.y,
    target.x - source.x
  )
  return {
    velocityX: Math.cos(angle) * speed,
    velocityY: Math.sin(angle) * speed
  }
}

// Creating a homing missile
function updateHomingMissile(missile, target, turnSpeed) {
  const targetAngle = Math.atan2(
    target.y - missile.y,
    target.x - missile.x
  )
  
  // Gradually rotate towards target
  const angleDiff = targetAngle - missile.rotation
  missile.rotation += Math.sign(angleDiff) * 
    Math.min(Math.abs(angleDiff), turnSpeed)
}

Conclusion

atan2 is a powerful tool in game development that solves the common problem of making objects face or move towards other objects. While the math behind it might seem complex, using it is straightforward once you understand the basics.

Remember the simple pattern:

const angle = Math.atan2(targetY - sourceY, targetX - sourceX)

With this knowledge, you can create engaging gameplay mechanics like homing missiles, tracking turrets, or enemies that face the player. The interactive demos above should help you visualize how atan2 works in practice.