Turret Rotation using Hingeconstraint Servo

Hello, so I’m trying to make a turret rotate to face the players mouse. I am using Hingeconstraint with Servo.
This is what it does right now

local Plr = game.Players.LocalPlayer
local PlrMouse = Plr:GetMouse()
PlrMouse.TargetFilter = script.Value.Value.Parent.Parent

local UIS = game:GetService('UserInputService')


local function turretFunction()
	
	local RadAngle = math.acos(math.clamp(script.Value.Value.CFrame.LookVector.Unit:Dot(PlrMouse.UnitRay.Direction), -1, 1))
	local VectorDot = script.Value.Value.CFrame.LookVector.Unit:Dot(PlrMouse.UnitRay.Direction)
	
	local DegAngle = math.deg(RadAngle)
	if VectorDot < 0 then
		script.Value.Value.HingeConstraint.TargetAngle = script.Value.Value.HingeConstraint.CurrentAngle - DegAngle
	elseif VectorDot > 0 then
		script.Value.Value.HingeConstraint.TargetAngle = script.Value.Value.HingeConstraint.CurrentAngle + DegAngle
	end
	
	
	
end
PlrMouse.Move:Connect(turretFunction)

Any idea how to fix it?

3 Likes

If I understand what you’re trying to do, the whole function can just be

local delta = PlrMouse.Hit.Position - script.Value.Value.CFrame.Position

script.Value.Value.HingeConstraint.TargetAngle = math.deg(math.atan2(-delta.Z, delta.X))

Not sure what you were trying to do with all the dots and stuff, maybe I misunderstood.

3 Likes

You should assign DegAngle directly to TargetAngle, not sum this value with the CurrentAngle.

That will fix the problem in the video, but you’ve got a problem with the math resolving the angle. The two vector’s used with Dot Product to find the cosine of the angle need to have the same origin. script.Value.Value.CFrame.LookVector is in world space so it’s origin is 0,0,0. According to the api; PlrMouse.UnitRay.Direction is not in world space, so it’s origin is CurrentCamera’s position.

You’ll want to use a vector from script.Value.Value.CFrame.Position to PlrMouse.Hit.Position instead of the UnitRay.

local vecA = script.Value.Value.CFrame.LookVector.Unit
local vecB = (PlrMouse.Hit.Position - script.Value.Value.CFrame.Position).Unit

local theta = math.acos(vecA:Dot(vecB))

This page has more information on using Dot Product with the inverse cosine to resolve theta.

Trying to find the angle between where the turret is pointing and where the player mouse is pointing so that it can turn accordingly.

Are you sure I don’t have to add/subtract with the CurrentAngle. Because the same problem is still happening with your code. My thought process is that since it is getting the angle between the two vectors it is not taking that into respect with how big of an angle it currently is. Also just realised that maybe I have to reset the target angle to 0 after?

Oh you’re right, issue is the vectors are backwards. My code should still fix the not of same origin issue. I think you should swap the vectors around so the mouse vector makes vector A, and the barrel makes vector B.

image
That way the resulting theta value is how far it needs to move to make vector B align with vector A.

You would need to project the vecB across the vecA space so it’s in 2d to get the exact angle of rotation around just the Y axis. Using inverse tangent like @nicemike40’s suggestion would remedy that issue. (Remember to find the mouse hit position vector that has the hingeconstraint as it’s origin)

1 Like

Like you want it to point towards where the cursor is in 3D space? The code I posted should do that.

Like @InfinityDesign said, just set TargetAngle directly instead of trying to add the delta and all that.

Yea so I used your code, and it works but only if I subtract 90 on the final angle, since for some it always faces 90 degrees away from the mouse position. Subtracting 90 fixes it, but is there another way to fix it?

Sure, rotate one of the attachment points 90 degrees or swap the x and z in the atan2 ( and play around with negatives).

1 Like

I know that it is a bit old but I’m really curious, may I know where does this formula come from?

Imagine a point (x,y) in 2D space. Imagine a line from the origin (0,0) to (x,y).

math.atan2(y, x) gives you the angle in radians that line makes with the X axis.

I use it here to get the rotation of the turret->mouse line in the XZ plane.

I use math.deg to turn the radians into degrees.

How do you know when you should do math.atan2(y,x) or math.atan2(x,y) without testing ?

Drawing out the trigonometry diagram helps.

@nicemike40 works but I believe will have an issue with a rotated base (tank turret).

The method below is the samething just with added ToObjectSpace to counteract the issue.

The axises are different as you might want to measure the horizontal or vertical angle.