Hello devforum,
I’m having some trouble making my turret system accurately aim at the mouse:
This happens when I use the 2 functions above to get the angles this happens:
However, when I use CFrame:ToEulerAnglesXYZ( ) it aims accurately, but it shows a different problem. It works only in π radians, when you want to aim to the opposite of that, the turret rotates in an inverse way:
This is the aiming problem when using CFrame:ToEulerAnglesXYZ()
Lastly, this is the code I’m using to rotate the turret:
game:GetService("RunService").Heartbeat:Connect(function()
local cf = CFrame.lookAt(part1.CFrame.Position, mouse.Hit.Position):ToObjectSpace(base.CFrame)
local cf2 = CFrame.lookAt(part2.CFrame.Position, mouse.Hit.Position)
local _, y, _ = cf:ToEulerAnglesXYZ()
local x, _, _ = cf2:ToOrientation()
if maxRotLeft == nil and maxRotRight == nil then
base.Joint.DesiredAngle = y
else
if math.clamp(y, maxRotLeft, maxRotRight) == y then
base.Joint.DesiredAngle = y
end
end
if math.clamp(x, maxDepression, maxElevation) == x then
part1.Joint.DesiredAngle = x
end
end)
Did you try using YXZ by itself, determining both X and Y rotation without any of the extra object space stuff? Id guess all of these things were attempted fixes but just to be sure
Euler angles can be annoying to work with sometimes, but you can work around it. The angle is correct, even when it seems reversed. The problem is that the angles past pi will be flipped across the y-axis on the unit circle. That’s just a quirk with this method. You can account for this for any angles that seem “opposite” by taking the inverse and subtracting pi.
That seems like an issue with Motor6Ds, you probably don’t want to switch them out for something else this late into the turret though. I guess another option would be to snap the angle back to zero once it crosses the 2pi line?
Is there a reason you can’t set the C0 or C1 of the motor and have to use desired angle? Using the benefits of CFrame:Lerp (and thereby quaternion double cover) will solve the positive/negative angle issue.
I’m having some problems limiting the rotation of the turret:
I tried to limit the turret to 100º, and it worked, but when i moved the mouse to the other side, the turret uses the shortest path. How could I do it so it takes the available path instead of a path that shouldn’t be used?
local function angleBetweenTwoVectors(a, b)
return math.acos(a:Dot(b))
end
local function rotateY(bX, bY, mouseDirY)
local cf = CFrame.new(base.Joint.C0.Position) * CFrame.Angles(bX, bY, mouseDirY + math.pi)
base.Joint.C0 = base.Joint.C0:Lerp(cf, 0.1)
end
local bX, bY, bZ = base.Joint.C0:ToEulerAnglesXYZ()
--local pX, pY, pZ = part1.Joint.C0:ToEulerAnglesXYZ()
--Making the turret point to the mouse.
game:GetService("RunService").Heartbeat:Connect(function()
local bcf = base.CFrame * CFrame.Angles(0, math.pi/2, 0)
local mouseHitY = bcf:ToObjectSpace(mouse.Hit)
local mouseDirY = math.atan2(mouseHitY.Z, mouseHitY.X)
local angleLVY = angleBetweenTwoVectors(base.CFrame.LookVector.Unit, part1.CFrame.LookVector.Unit)
local angleMouseY = angleBetweenTwoVectors(base.CFrame.LookVector.Unit,(mouse.Hit.Position - base.CFrame.Position).Unit)
--Moving the turret in the Y axis.
if math.clamp(angleLVY, maxRotLeft, maxRotRight) == angleLVY then
rotateY(bX, bY, mouseDirY)
else
if math.clamp(angleMouseY, maxRotLeft, maxRotRight) == angleMouseY then
rotateY(bX, bY, mouseDirY)
end
end
bX, bY, bZ = base.Joint.C0:ToEulerAnglesXYZ()
end)