How do I return a negative angle value if a part is facing away 'leftwards' from a point?

Hey all. So I have this simple code that allows me to get an angle between a part’s position + direction, and a point in the world.

My current technique only returns angles in the interval [0; 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 pi radians = 180 degrees . This means the angle you get in this way has no direction (it’s never negative). How can I fix this?

The part here is facing ‘right’ away from the red block and returns a positive angle value (which is good)

But this time, the part here is facing ‘left’ away from the red block and STILL returns a positive angle value (I need it to return a negative value in this case. How do I fix this?)

local function GetAngleBetween(PosA, PosB)
	return math.acos(math.clamp(PosA:Dot(PosB), -1, 1))
end

while true do
	wait()
	local CameraLookVector = script.Parent.CFrame.LookVector
	local LookToPoint = (workspace.RedBlock.Position - script.Parent.Position).Unit
	
	local AngleBetween = GetAngleBetween(CameraLookVector, LookToPoint) -- In radians
	
	print(AngleBetween) -- Always returns a positive value which is the problem.
end

If the positive value is larger than 180, subtract 360 from it.

in the pictures above, the blue block never reaches an angle of 180 degrees. In the ones above, its about 40 degrees.

This is the block that is facing left you are referring to?

no. Both. Both of them have an angle difference of 40 degrees. which is the problem. The one facing left should be -40, but the code will always return a positive angle value

Im not sure if this helps, but maybe BasePart | Roblox Creator Documentation might work

I cant use this as .Orientation is set in world space. The code above uses object space. Not world space.

You could just normalize the LookVector.X to -1 or 1 and multiply it by your angle. I’m not sure if their is a better way of doing this but here’s a quick and easy example of what I mean.

local sign = math.clamp(part.CFrame.LookVector.X * 10, -1, 1)
sign = if sign == 0 then 1 else sign

Edit: Forgot to account for situations in which the player is facing directly towards or away from the point (where the value would be equal to 0).

This works for rotation, but doesn’t seem to work with moving the camera sideways.

wait()
	local CameraLookVector = script.Parent.CFrame.LookVector
	local LookToPoint = (workspace.RedBlock.Position - script.Parent.Position).Unit

	local AngleBetween = GetAngleBetween(CameraLookVector, LookToPoint)
	
	local DirectionalAngleBetween = math.clamp(CameraLookVector.X, -1, 1)
	DirectionalAngleBetween = if DirectionalAngleBetween == 0 then 1 else DirectionalAngleBetween
	
	print(math.deg(DirectionalAngleBetween * AngleBetween))

By sideways, do you mean you stay facing the point but move to the left and right? And in such situations you’d like it for the value to be negative if the player is on the left-hand side of the point and vice-versa for the right-hand side?

1 Like

Correct. I need this as I the returned angle always needs to be a “directive” angle (negative angle if left, positive if right).

image

What about this situation where the blue part is facing the red part and coming from the opposite side. Do you want it to then flip the sign? Where this would result in a positive angle because from the blue part’s perspective it is on the right side?
Capture.PNG

In that situation, the blue part’s arrow is going left from it’s perspective. Therefor, it should be a negative value. Think of changing an angle value in roblox’s hinges. It’s supports negative and positive numbers for directional reasons.


EDIT: The +Angle and -Angle in this image are suppose to be the other way around. You should get my point anyway though.

Well if you just want to know where the part is on the left or right side of the point, from a top-down perspective, you can just compare the x values.

local x = math.clamp(part.Position.X - point.Position.X, -1, 1)
x = if x == 0 then 1 else x

tan=opposite/adjacent. You could you lookVector to determine the player/camera direction to decide if x or z is the opposite or hypotenuse. Personally, this is what I did for a angle list script to prevent drag with position, by forcing it to an angle that wouldn’t have drag if it was below that angle and then lowering the angle when it got near.

local Xdifference = (CameraPointPosition.X - RedBlock.Position.X)
local Zdifference = (CameraPointPosition.Z - RedBlock.Position.Z)

local angle = math.atan(Xdifference/Zdifference) -- can change depending on direction

There isn’t anything here defines the direction of the camera. So this wouldn’t work.

What I would do is make a fake cframe to make to object space based off of both the parts like so
this might help to change the look to point by changing it on the red part exactly

local Fake = CFrame.lookAt(BlueBlock.Position,RedBlock.Position)
local LookToPoint = Fake.Position + Fake.Lookvector

lookVector - “Am I joke to you.”

If it got a CFrame it got a lookVector.

There’s literally no LookVector or CFrames in your provided code. Do I have add something else onto this or use this in my current code somewhere or am I missing a curtail step to this?

Well you can figure that out but I’ll write it out for you.

tan0=opposite/adjacent

function getDirectionalTan(PerspectiveCFrame, XDistance, ZDistance)
	local tan = 0
	local lookVectorX = math.abs(math.round(PerspectiveCFrame.lookVector.X))
	if lookVectorX == 0 then--Player looking x direction so use Z as opposite, and X as adjacent
		tan = (ZDistance/XDistance)--tan number
		else--Looking z direction so use X as opposite, and Z as adjacent
	tan = (XDistance/ZDistance)--tan number
end

return tan--return tan number
end

function getAngle(CameraCFrame, PartPosition)
	local CameraPosition = CameraCFrame.Position
	local XDistance = PartPosition.X - CameraPosition.X
	local ZDistance = PartPosition.Z - CameraPosition.Z

	local angle = math.atan(getDirectionalTan(CameraCFrame,XDistance, ZDistance))--Run tan math function
	
	return angle
end

local angle = getAngle(Camera.CFrame, Part.Position)--fix paraemetre to ur variables, and tadaaa