# How to calculate angle for shooting bullet in 3D?

What I want to know is if I can calculate an angle similar to how I'm doing in 2D and update the x,y,z position of a bullet based on that angle in a similar manner I'm doing the update function below.

I wrote this function in Ruby to find the target angle between two 2D (x,y) vectors, but now I want to find out how to do this in 3D in a similar way:

  def target_angle(point1, point2)
x1 = point1
y1 = point1
x2 = point2
y2 = point2
delta_x = x2 - x1
delta_y = y2 - y1
return Math.atan2(delta_y, delta_x)
end


Given an object (like a bullet in this case), I can shoot the object given a target_angle between the player (x,y) and the mouse (x,y), as such in the bullet update function:

  def update
wall_collision
# the angle here is the target angle where point 1 is the player and
# point 2 is the mouse
@x += Math.cos(angle)*speed
@y += Math.sin(angle)*speed
end


Is there a similar method to calculate a target angle in 3D and use that angle in a similar manner as my update function (to shoot a bullet in 3D)? How can I make this work for two 3D vectors (x, y, z), where you have the player position (x,y,z) and some other arbitrary 3d point away from the player.

Instead of finding the angle using atan2 and then reconstructing the vector using sin and cos you can store the direction using a normalised vector.

This works in both 2D and 3D.

  def target_angle(point1, point2)
x1 = point1
y1 = point1
x2 = point2
y2 = point2
@delta_x = x2 - x1
@delta_y = y2 - y1

len = Math.sqrt(@delta_x*@delta_x+@delta_y*@delta_y);
@delta_x = @delta_x / len;
@delta_y = @delta_y / len;
end

def update
wall_collision
# the angle here is the target angle where point 1 is the player and
# point 2 is the mouse
@x += @delta_x*speed
@y += @delta_y*speed
end


To do it in 3D just add the math for z the same way x and y are calculated.

len = Math.sqrt(@delta_x*@delta_x + @delta_y*@delta_y + @delta_z*@delta_z);


You can even ditch speed and store it right inside delta_x, delta_y, and delta_z by multiplying them by speed after the division by len to normalise them into a unit vector.

    @delta_x = @delta_x / len * speed;
@delta_y = @delta_y / len * speed;


...

    @x += @delta_x
@y += @delta_y


So the whole thing in 3D becomes:

  def target_angle(point1, point2)
x1 = point1
y1 = point1
z1 = point1
x2 = point2
y2 = point2
z2 = point2
@delta_x = x2 - x1
@delta_y = y2 - y1
@delta_z = z2 - z1

len = Math.sqrt(@delta_x*@delta_x + @delta_y*@delta_y + @delta_z*@delta_z);
@delta_x = @delta_x / len * speed;
@delta_y = @delta_y / len * speed;
@delta_z = @delta_z / len * speed;
end

def update
wall_collision
# the angle here is the target angle where point 1 is the player and
# point 2 is the mouse
@x += @delta_x
@y += @delta_y
@z += @delta_z
end


This way 2D is just 3D where z is always zero (so it is removed). The code is otherwise identical in working principle.

• Note: speed could be multiplied once by baking it into len by doing len /= speed before the 3 delta_xyz divisions but I wanted to keep the example simple and not refactor too much of the code. Using a reciprocal for len and 3 multiplications instead would also be faster, but again: KISS for the sake of example. Aug 20, 2018 at 19:22
• I used this and it works! Aug 20, 2018 at 20:29