I thought of some stuff and figured out how to do it.
First of all, limiting horizontal movement is pretty easy, you just substitute the y value in the target position with the rotating parts y position. It allows for the individual change of the horizontal axis.
local lookat = limitTurn(part.CFrame, Vector3.new(root.Position.X, part.Position.Y, root.Position.Z), 10, dt)
part.CFrame = lookat
In this case, “part” is the rotating part, “root” is just the humanoidrootpart.
For vertical rotation, it was a lot harder for me to find something that worked.
What I came up with for doing it was,
getting the distance between the part and the root part,
then multiplying the unit of the rotating part’s lookvector, by the distance.
I would replace the Y in the vector3 obtained from that with the root part’s Y position.
I would then add on the X and Z positions of the rotating part to that vector3, so it is properly offset.
In code, this is what that looks like.
local dist = (Vector3.new(root.Position.X, root.Position.Y, root.Position.Z) - part.Position).Magnitude
local lookVector = part.CFrame.LookVector.Unit * dist
local XYlookvector = Vector3.new(lookVector.X, root.Position.Y, lookVector.Z)
local lookat = limitTurn(part.CFrame, Vector3.new(part.Position.X, 0, part.Position.Z) + XYlookvector, 50, dt)
part.CFrame = lookat
So, if I wanted to do both simultaneously, it would look like this.
game:GetService("RunService").Stepped:Connect(function(_,dt)
local player = game.Players:GetPlayers()[1]
local character = player.Character
local root = character.HumanoidRootPart
local dist = (Vector3.new(root.Position.X, root.Position.Y, root.Position.Z) - part.Position).Magnitude
local lookVector = part.CFrame.LookVector.Unit * dist
local XYlookvector = Vector3.new(lookVector.X, root.Position.Y, lookVector.Z)
local lookat = limitTurn(part.CFrame, Vector3.new(part.Position.X, 0, part.Position.Z) + XYlookvector, 50, dt)
part.CFrame = lookat
lookat = limitTurn(part.CFrame, Vector3.new(root.Position.X, part.Position.Y, root.Position.Z), 10, dt)
part.CFrame = lookat
end)
Since the function remains unchanged, this is all you would have to do.
If you have problems with it, just let me know.
Edit: Apparently the order of horizontal and vertical rotation changes mattered. If horizontal went first, it could only rotate horizontally when it vertically rotated. Once I swapped the order, to being
vertical->horizontal It seemed to work fine.