How to control a turret using mouse deltas?

Hey, I have a turret that rotates on a HingeConstraint, powered by an AlignOrientation. The player’s camera is set to scriptable, and its CFrame is set to that of the tip of the turret’s barrel. The player’s mouse is also locked.

How do I translate the player’s mouse deltas into a CFrame or vector that can be used by the AlignOrientation? I’ve searched everywhere over the DevForum, but nothing seemed to solve my problem.

You can apply a rotation based on the mouse movement using something like:

local currentCFrame = CFrame.new() -- Probably should be initialized to the camera CFrame instead

local upRotation = CFrame.Angles(math.deg(1), 0, 0)
local rightRotation = CFrame.Angles(0, math.deg(1), 0)

-- Do a connection to the mouse movement to get the X and Y delta
local sensitivity = 0.5 -- Tune this value, perhaps divide the X and Y based on the size of the screen
local deltaX = -- Get from the mouse movement
local deltaY = -- Get from the mouse movement
-- Apply horizontal rotation (world relative)
currentCFrame = (CFrame.Angles(math.deg(deltaX * sensitivity), 0, 0)) * currentCFrame
-- Apply vertical rotation (CFrame relative)
currentCFrame = currentCFrame * (CFrame.Angles(0, math.deg(deltaY * sensitivity), 0))

You can also just store a rotation value and create a new CFrame each time:

local xRotation = 0 -- Up and down
local yRotation = 0 -- Right and left

-- TODO: update xRotation and yRotation based on the deltaY and deltaX, respectively
-- Ex: xRotation += deltaY * sensitivity

local currentCFrame = CFrame.Angles(math.deg(xRotation), math.deg(yRotation), 0)

Either of those two methods should work if my math is right.

Just tried both of those solutions, neither worked. The turret acts all glitchy (dozens random tiny movements/jerks every second). Here’s my adapted version of your code:
(vertical rotation and horizontal rotation are controlled by two separate AlignOrientations)

local player = game.Players.LocalPlayer
local character = player.Character
local userInputService = game:GetService("UserInputService")
local camera = workspace.CurrentCamera

local mouse = player:GetMouse()

mouse.TargetFilter = workspace

camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = script.Shoot.Value.CFrame
userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter

mouse.Move:Connect(function()
	print("moved")
	
	local upRotation = CFrame.Angles(math.deg(1), 0, 0)
	local rightRotation = CFrame.Angles(0, math.deg(1), 0)

	-- Do a connection to the mouse movement to get the X and Y delta
	local sensitivity = 0.5 -- Tune this value, perhaps divide the X and Y based on the size of the screen
	local deltaX = userInputService:GetMouseDelta().X -- Get from the mouse movement
	local deltaY = userInputService:GetMouseDelta().Y -- Get from the mouse movement
	-- Apply horizontal rotation (world relative)
	script.YRotator.Value.AlignOrientation.CFrame = (CFrame.Angles(math.deg(deltaX * sensitivity), 0, 0)) * script.YRotator.Value.AlignOrientation.CFrame
	-- Apply vertical rotation (CFrame relative)
	script.Barrel.Value.AlignOrientation.CFrame = script.Barrel.Value.AlignOrientation.CFrame * (CFrame.Angles(0, math.deg(deltaY * sensitivity), 0))
end)

game:GetService("RunService").RenderStepped:Connect(function()
	camera.CFrame = script.Shoot.Value.CFrame
	userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
end)

If you have two AlignOrientations they will fight each other and become glitchy (unless you’ve messed with the AlignType such that each AlignOrientation only aligns on their individual axes).

Does the turret have multiple HingeConstraints? You should be able to get away with just having one AlignOrientation in the end of the turret. If that doesn’t work though, I believe there is a way to set the AlignType such that it only works around one axis.

I’ll send you a PM on how to do this…

The turret is split into two separate parts like a tank turret, using two HingeConstraints. They rotate on different axes.

1 Like

Boost, I’d like an answer as soon as possible.

Can you send a model or picture of your turret? One way you can get the individual AlginOrientations to only work on one axis is to set the Mode to TwoAttachment then have the Attachment1 inside “base” of the joint

For example, for rotating around horizontally, assuming your turret’s first joint is between the mount of the turret and the horizontal rotation assembly, you could have the Attachment0 inside the horizontal rotation assembly and your Attachment1 inside the mount of the turret (ex: the tank, a car, the ground, etc) and only rotate Attachment1 on it’s Y axis (so only rotate it horizontally).

If you show how your turret is set up it would be easier to explain.

1 Like

I made this little turret as an example:

If you look at the picture, see how the AlignOrientations (shown with the yellow arrows with the blue lines between Attachment0 and Attachment1) go between the same assemblies as the joints (ex: between the base and the rotating platform). Then, to control the AlignOrientations, the attachment in the base is rotated relatively using the Attachment.CFrame property. This way the two AlignOrientations never conflict because they’re each rotating on perpendicular axes (ex: vertical and horizontal relative to the turret).

(Using both the Attachment0 and Attachment1 makes the AlignOrientation try to line up Attachment0 with Attachment1, so we can rotate Attachment1’s CFrame to change the goal.)

Here is a model file:

TurretExampleDevForum.rbxm (7.6 KB)

And here is a place file:

TurretExampleDevForum.rbxl (59.8 KB)

Currently the code in the turret just rotates each joint to a random direction every 5 seconds, but you can easily modify it to either use internally stored rotation values or to apply offsets each time you get new deltaX and deltaY (using a multiplication of the current Attachment.CFrame times CFrame.Angles(...)).

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.