I was working on simple tank turret system which uses HingeConstraints to align turret vertically and horizontally with mouse position of player. I managed to get horizontal alignment work perfectly but had serious issue with vertical alignment.
System works like this:
There are 3 parts which include MainPart (only non-transparent part on image), TurretAxis (half transparent part above MainPart with horizontal hinge) and ElevationAxis (one at the main gun with vertical hinge)
(Another picture with attachmenents of those two hinges at same position to reduce possible confussion)
So my problem is that in some cases the vertical angle is not calculated correctly and I seem to can’t find actual reason why. It’s most likely with math module which I might not use correctly in my goals.
(For next pictures small explanation: red highlighted part is mouse position aka where the gun should aim and green one is current position of gun aim)
Example of correct alignment:
Examples of not correct alignment:
And heres the how the code works:
Theres local script which does all calculations and sends them to server via RemoteEvent:
local tank = workspace["M113 APC"].Misc
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()
local event = game.ReplicatedStorage.TankThingy
game:GetService("RunService").RenderStepped:Connect(function()
workspace:WaitForChild("Part2").Position = mouse.Hit.Position
mouse.TargetFilter = workspace:WaitForChild("Part2")
-- HORIZONTAL ANGLE CALCULATIONS
local baseAttachment1 = tank.Part1.TurretAttachment0
local object_horizontal_offset = (baseAttachment1.WorldCFrame):PointToObjectSpace(mouse.Hit.Position)
local yaw = math.atan2(object_horizontal_offset.Y, -object_horizontal_offset.Z)
-- VERTICAL ANGLE CALCULATIONS AKA MAIN PROBLEM
local turretOrigin = tank.ElevationAxis
local x = math.abs(mouse.Hit.Position.X - turretOrigin.Position.X)
local y = math.abs(mouse.Hit.Position.Y - turretOrigin.Position.Y)
local z = math.abs(mouse.Hit.Position.Z - turretOrigin.Position.Z)
local pitch = math.atan2(y, x)
if math.deg(math.atan2(y, z)) < math.deg(math.atan2(y, x)) then
pitch = math.atan2(y, z)
end
if mouse.Hit.Position.Y <= turretOrigin.Position.Y then
pitch = -pitch
end
--print(math.deg(math.atan2(y, z)), math.deg(math.atan2(y, x)))
event:FireServer(math.deg(pitch), math.deg(yaw))
end)
And theres server script inside the tank:
local event = game.ReplicatedStorage.TankThingy
local pitchAxis = script.Parent.Parent.TurretAxis.ElevationHinge
local yawAxis = script.Parent.TurretHinge
local p = workspace:WaitForChild("Part3")
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = script.Parent.Parent.Parent:GetDescendants()
event.OnServerEvent:Connect(function(Player, Pitch, Yaw)
pitchAxis.TargetAngle = Pitch
yawAxis.TargetAngle = Yaw
local result = workspace:Raycast(script.Parent.Parent.ElevationAxis.Position, script.Parent.Parent.ElevationAxis.CFrame.LookVector * 1000, params)
if result then
if result.Position then
p.Position = result.Position
end
end
end)
Note
Server script has raycast part of code which is responsible for current aim position so it’s not affiliated with problem, its mostly in the local script.
Thank you in advance and sorry for any grammatical errors, English isn’t my mother tongue.