Rotate a part using mouse (Y axis)

Hello, I’m trying to make towers rotate based on where I’m aiming my mouse on the Y axis only.
Here’s my localscript:

local rs = game:GetService("ReplicatedStorage")
local plr = game:GetService("Players").LocalPlayer
local mouse = plr:GetMouse()
local RunService = game:GetService("RunService")

RunService.RenderStepped:Connect(function()
    local character = plr.Character or plr.CharacterAdded:Wait()
    local mousePos = mouse.Hit.Position
    if character then 
        local rootPart = character:FindFirstChild("HumanoidRootPart")
        if rootPart then 
            local direction = Vector3.new(mousePos.X - rootPart.Position.X, 0, mousePos.Z - rootPart.Position.Z)
            local angleY = math.atan2(direction.X, direction.Z)
            rs.Events.Boat.TowersManager:FireServer(angleY)
        end
    end
end)

Script (Event called from localscript ) :

rs.Events.Boat.TowersManager.OnServerEvent:Connect(function(player, angleY)
    local boat = player:FindFirstChild("currentBoat")
    if boat and boat.Value then 
        local boatObject = boat.Value
        for _, tower in pairs(boatObject:GetChildren()) do
            if tower:IsA("Model") and tower.Name:sub(1,5) == "Tower" then
                for _, part in pairs(tower:GetChildren()) do 
                    if part:IsA("MeshPart") and part.Name == "Tower" then
                        part.CFrame *= CFrame.Angles(0, angleY, 0)
                    end
                end
            end
        end
    end
end)

My problem is that they all don’t do what I want and just go around in circles.

2 Likes

You are multiplying the angleY CFrame by the current CFrame every time which is like giving it a velocity to spin at:

part.CFrame *= CFrame.Angles(0, angleY, 0)

To make this work you need to save the original CFrame when the player first clicked, and multiply by that instead.

1 Like

??? Can you give more details please?

1 Like

It’s not looking at all at my mouse in any case


image

1 Like

When you do *= you are multiplying the current CFrame by an angle, then replacing part.CFrame with it. So the next time this statement runs, that angle has already been applied, and then you apply it again, so it will just spin the part. You want to instead multiple your angle by some constant CFrame, either a default orientation or what it was when you first clicked.

1 Like

Are you trying to make it point at where the mouse is on screen?

1 Like

Yes, that’s what I want to do.

Theres a few ways to do it and they all feel slightly different and will involve a different amount of geometry work. Do you have an example of how you want it to look, like a clip from another game?

Well, no? I just want the turret to rotate on the Y axis depending on where I aim my mouse.

But there are a lot of ways it could work and only you can figure out which one will be best. Should it work like you are grabbing a ring around the part, which is how Kerbal Space Program works? Should it aim the barrel at the mouse in 3D space? or do you just want to set the angle based on the angle the mouse makes with where the player first clicked, which is how Blender does it.

Like in World of warships, the turret is aiming where you’re aiming with your mouse, but I would like only on the Y axis.

image

So like turning left and right? I think this would be better if it pointed in the direction where your camera was, with some more precise aiming/movements connected to mouse movements, instead of everything just being where the mouse is on the screen.

Ok, this is relatively easy to do. I will give you the outline, let me know if these steps make sense.

  1. Get the 3D point the mouse is pointing at
  2. Get the pivot point of the turret from which you want to aim
  3. Set the Y component of the mouse point to be the same as the Y component of the pivot point. This will make it so there is no vertical component to the following rotation.
  4. Subtract the pivot point from the mouse point
  5. Use CFrame.LookAt to create a CFrame that looks from the pivot point to the mouse point. This CFrame is how the turret should be oriented in World space.
  6. If the turret is mounted via a constraint, you need to convert this rotation to the space of the mounting point.

I also have some code you can look at that does almost exactly what you want, but I do not remember exactly how it works: Boatgun - Roblox

Though I don’t know why exactly you are doing it this exact way, when an easier way would to just get the hitpoint of where the mouse is, and just use that 3d point as a direction, and ignoring height, so it turns the guns left and right but doesn’t point it up or down.

“Get the pivot point of the turret from which you want to aim” what ? How?

Wherever the turret sits. If it’s on a vehicle that point will change which will affect the answer. I use the position of the part the turret sits on. It should be aligned with the axis of rotation.

I’ve done this:

rs.Events.Boat.TowersManager.OnServerEvent:Connect(function(player, mousePos)
	local boat = player:FindFirstChild("currentBoat")
	if boat and boat.Value then 
		for _, tower in pairs(boat.Value:GetChildren()) do
			if tower:IsA("Model") and tower.Name:sub(1,5) == "Tower" then
				local t = tower.PrimaryPart
				local pivot = t.Position
				local direction = mousePos - pivot
				local turretCFrame = CFrame.lookAt(pivot, mousePos)
				t.CFrame = turretCFrame
			end
		end
	end
end)

It works but I can do better, it does all axis, how to have only Y?

Pretty sure there’s a way to do exactly that, but a brute force sloppy solution is to just take the Y of the mousePos, and set it to the Y of the turret or something, that way the Y of the two is equal and it just points based on Z and X. Though, @azqjanna can give you the actual function that does this efficiently, because I’m sure it exists, but both should work.