Rotating turret using hinge constraints

How can I go about making a turret rotate using hinge constraints and follow the mouse position?

Like this:

I want the base hinge to move on the X and/or Z axis (left and right), and for the turret hinge to move only on the Y axis (up and down).

I have made a rotating turret before using BodyGyro’s, but since those are deprecated I’m looking for a new more efficient way of doing this.

Any help appreciated!

First you gotta convert the target position into the space of the turret base, the non-rotating part. You can then find the yaw angle by doing atan2() on the X and Z components of that position. (assuming the base has its Y axis up).

Could you explain the maths or give an example?

yeah read this

cuberotate.pdf (368.8 KB)

I’ve actually done something like this multiple times. You would want to grab the 3D position of the mouse using mouse.Hit then also use CFrame.LookAt(BasePosition, mouse.Hit), and feed the orientation’s X-axis of the resulting CFrame to the base’s Servo, Servo as in the Actuator type usually found in Motors, Hinges, Cylindrical Constraints etc… You would want to do the same for the turret’s servo but feed the orientation’s Y-axis.

This is over 3 years old but still works;


2 Likes

What is filter?

Also does CFrame bypass the AngularSpeed on the hinge(servo)? Because I would also want to set different rotate speeds for different turrets.

love your rocket launcher btw!

The CFrame class actually has a helper function just for this, since it’s such a common task: Roblox API CFrame:PointToObjectSpace
or you can just do the multiplication yourself like turretAttachment.WorldCFrame:Inverse() * targetPoint where the targetPoint is the world-space location as a Vector3. You generally want the target position in the coordinate space of the hinge itself, don’t use Part CFrames or you’ll have to manually account for the offsets. If you find yourself getting confused about the hinge attachments being 90-degrees off from how your brain thinks of things, you can always just add an extra reference attachment to each moving part, at the same location as the hinge pivot.

You first need to get the target point in world space, because your mouse position is a point in 2D screen space. Normally, you’d use Camera:ViewportPointToRay() to get a ray that you can use to do a raycast from the camera location into the world, and the use the RaycastResult.Position as your target point.

Once you have the target position in the space of the hinges, it’s just some basic triangle trig to work out the Euler angles you need for setting the hinge servo angles. It’s just Spherical Coordinates so you can just read the solution there on Wikipedia.

2 Likes

It uses the Orientation associated with the CFrame which is fed into the Servo/Hinge’s TargetAngle property, which wouldn’t bypass the AngularSpeed. Filter is just a regular part, which I set the CFrame to in order to grab the orientation from. I did this because 3 years ago I was terrible so instead I would recommend using CFrame:ToEulerAnglesXYZ(), then converting the radians to degrees using math.deg() to get the orientation instead.

But where is this part? Is it on your rocket launcher? Is it an invisible part?

Also, I’m making this server side, so I need to get the orientation value over to the server.

assuming you havent done this already, you dont need to make it go to the server when its stuff like target angles etc, its actually better to keep it local because theres then less lag

So I used your script @ClearlyVi i copied it almost identically

--Imports
TWS=game:GetService("TweenService")

--Variables relating to the turret
local Turret= script.Parent
local Barrel= Turret.Barrel
--SETTINGS
local aggroRange=100
local bulletDamage=10
local processorTime=0.5

local Filter=Instance.new("Part")

local function aim(Positon)
	local positionToAim=CFrame.lookAt(script.Parent.RotateZ.Hinge.Position,Positon)
	
	Filter.CFrame=positionToAim
	Turret.RotateY.HingeConstraint.TargetAngle=(Filter.Rotation.Y+90)
	Turret.RotateZ.HingeConstraint.TargetAngle=(Filter.Orientation.X)
end




while true do
	for i,v in workspace:GetChildren() do
		if v:FindFirstChild("Humanoid") and (v.HumanoidRootPart.Position-Turret.Base.Middle.Position).Magnitude<100 then
			aim(v.HumanoidRootPart.Position)
		end
	end
	wait(processorTime)
end

But when I play the game the turret only has Positive angles, meaning that it does not follow the player if you are behind it



As you can see the turret mirros it on the other side for some reason
Pay attention to the target angle value here