pixel.rip

Getting Angles Between Two Objects with `atan2`

2024-11-21 in codex

Goal

Fire a projectile between two objects. The projectile should be “aimed” at the target object, but should not track the target if it moves.

Solution

Playable Example

Playable Example - GitHub

How it Works

We have two objects in the game. In this case the orange guy and the red guy. First things first, we’ll need a way to get the angle from the orange guy (src) to the red guy (tgt).


function get_angle(src,tgt)
	local y2=tgt.pos.y  
	local x2=tgt.pos.x  

	local y1=src.pos.y  
	local x1=src.pos.x 

	return atan2(y2-y1,x2-x1)
end

I won’t (ok, can’t) explain what atan2() does exactly, but I do know that if we give it the y distance between our objects, followed by the x distance, we’ll get the angle between the two objects (something between 0 to 1). Trig, right?

So next we create a bullet object that has an angle and speed:


function fire_bullet(src,tgt)
	local bt={}
	bt.spr=3
	bt.x=src.x
	bt.y=src.y
	
	bt.ang=get_angle(src,tgt)
	bt.speed=2
		
	add(bullets,bt)	
end

With the angle and speed attached to each bullet in the bullets table we just need to make sure they move using sin() and cos() on the x and y on every frame.


-- in our update()
for bt in all(bullets) do
	bt.x += sin(bt.ang) * bt.speed 
	bt.y += cos(bt.ang) * bt.speed
end

I hear you saying “what the hell do sin() and cos() have to do with moving bullets on an angle?” Good question! I did my best to explain that here: Sin and Cos for Movement.