Best way to get the angle between two vectors?


#1

For my NPC system, I’m looking to have the NPC rotate their head to look at you (obviously with rotation limits). The desired effect will look something like this:

To rotate the head, I use tween service. In the example above, I did:

CFrame = head.CFrame * CFrame.fromEulerAnglesXYZ(0,math.rad(45))

My question is, what’s the easiest way to get the angle required for the NPC to look at the player?

CFrame = head.CFrame * CFrame.fromEulerAnglesXYZ(0,math.rad(θ))

I could use trigonometry, I’m just curious to know if there’s an easier way to obtain the desired angle?


#2

This should work.

CFrame.new ( Vector3 pos, Vector3 lookAt )
head.CFrame = CFrame.new(head.Position,Vector3.new(playerHumanoidRootPart.Position.x,head.Position.y,playerHumanoidRootPart.Position.z))


#3

Perfect, thanks!


#4

SebastianAurum provided the best way of solving OPs actual problem, but in case someone in the future really does need to find such an angle, here’s how you can do that:

First of all, you can’t find an angle between two points. It just doesn’t make any sense, because an angle needs at least three points to be properly defined: a point each on the legs of the angle, and one for the point/knee of the angle. In OPs case, it looks like they’re really asking for the angle between two vectors, which does make sense (the vector from NPCs head to players head, and vector of direction of NPCs head).

The angle between two vectors a and b is

math.acos( a:Dot(b)/(a.Magnitude * b.Magnitude) )

We often deal with the special case where both vectors are unit vectors (i.e. their magnitude is 1), in which case this slightly simpler expression that you might see being used elsewhere works as well:

math.acos( a:Dot(b) )

This technique only returns angles in the interval [0; 2 pi] because two vectors can never point more away from each other than directly away from each other, which can always be achieved by a rotation of 2 pi radians = 180 degrees. This means the angle you get in this way has no direction (it’s never negative), so if you need that direction you’ll need a different technique:

First of all, this method works best with a CFrame and a vector (could also use 3 vectors), and then gets the angle between the CFrame’s lookVector and the given vector. Because the CFrame has an upVector as well, we can work with the direction:

local projectedVector = cframe:VectorToObjectSpace(vector) * Vector3.new(1, 0, 1)
local angle = math.atan2(projectedVector.Z, projectedVector.X)

This works by projecting the vector onto a 2D plane perpendicular to the upVector of the cframe, and converted to a representation that is in relation to the cframe. It then uses atan2 to calculate the angle between the lookVector of the cframe and the vector in that plane.


#5

Thanks for the clarification, that’s a very helpful explanation.