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.
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.
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?
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.
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.
Get the 3D point the mouse is pointing at
Get the pivot point of the turret from which you want to aim
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.
Subtract the pivot point from the mouse point
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.
If the turret is mounted via a constraint, you need to convert this rotation to the space of the mounting point.
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.
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.
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.