Hey so I’ve been trying to make a system where it detects which direction the player is moving relative to the camera.
I’ve used math.acos so calculate the direction but it returns 90 degrees regardless of whether I’m moving left or right. Im pretty sure I need to use math.atan2 for this but I’m not quite sure how to implement it and get similar results.
My script right now:
local character = script.Parent
local humanoid = character.Humanoid
local camera = game.Workspace.CurrentCamera
local function updateAngle()
local playerMoveDirection = humanoid.MoveDirection
if playerMoveDirection.Magnitude == 0 then return end
local playerXZ = Vector3.new(playerMoveDirection.X, 0, playerMoveDirection.Z)
local cameraLookDirection = camera.CFrame.LookVector
local cameraXZ = Vector3.new(cameraLookDirection.X, 0, cameraLookDirection.Z)
local dotProduct = playerXZ:Dot(cameraXZ)
local playerMagnitude = playerXZ.Magnitude
local cameraMagnitude = cameraXZ.Magnitude
local cosAngle = dotProduct / (playerMagnitude * cameraMagnitude)
cosAngle = math.clamp(cosAngle, -1, 1)
local angle = math.acos(cosAngle)
local angleDegrees = math.deg(angle)
print(angleDegrees)
end
game:GetService("RunService").RenderStepped:Connect(updateAngle)
Also if you could provide an explanation to how math.atan works that would help me use it in the future. Thanks!
local signedAngle = math.atan2(
playerXZ:Cross(cameraXZ).Y,
playerXZ:Dot(cameraXZ)
)
math.atan2 is similar to math.atan, however solves for the full quadrant (i.e. -180 degrees → 180 degrees). math.atan will only solve for -90 degrees → 90 degrees. The way I try to visualise it is the difference between considering a right-angled triangle vs a full 360 degree circle.
With atan you pass the (x/y) where the x and y are the perpendicular ‘opposite’ and ‘adjacent’ sides of the triangle, but it’s not great at differentiating when you start getting negative angles/lengths.
With atan2 it will consider the entire range of quadrants and return a representative value that respects the full-circle of angles.
atan is a trigonomic function which from what i got from 5 minutes of searching, is the inverse of the tangent function.
The Roblox wiki uses a very technical description of these functions considering atan2 mentions Returns the arc tangent of y/x (in radians) while using the signs of both parameters to find the quadrant of the result. It also handles correctly the case of x being zero.
I dont know what this means, like at all.
Regardless, you should look into how trigonomic functions work and relate, and also these functions work in radians, not degrees, though you can convert between the two using math.rad and math.deg respectively.
Thank you so much! This fixed my issue with my code. But just because I like to know how my code works why did you use :Cross() and :Dot() for the y and z values? And if playerXZ and cameraXZ both have a Y value of 0 then why does printing the playerXZ:Cross(cameraXZ).Y give me a few decimals more than 0? An explanation or redirection to any articles will be greatly appreciated in order to grow my roblox scripting knowlage.
So dot product determines how parallel two vectors are, and a cross product produces a new vector that points ‘up’ relative to the two vectors.
With the magnitude relating to the angular difference between the two. As our cross-product is pointing ‘up’, and since both playerXZ and cameraXZ have their Y components set to 0, the Y component of the resulting cross product will give you a value representing how much one vector “turns” relative to the other in the horizontal plane.
In essence, using the Y component of the cross product allows you to determine the rotational direction, while the dot product provides the alignment.
I’m not great at explaining this stuff, but I’d recommend reading up about vectors and computing angles.
Thank you so much for the explanation! You’ve really helped alot in helping me understand this kinda stuff, and thanks for coming back to explain everything!