Tank Control (Turret/Barrel) system not working on slope

Hello there, I am having an issue with my tank control system. My goal is to make the tank point at a certain point (the player’s mouse position in 3D). The way I am initially doing this is simple: Call CFrame.lookAt() with the turret’s position and the point’s position, I convert it to orientation values using the CFrame:ToOrientation() function, and then I simply set the turret angle of the tank equal to the Y angle returned by the ToOrientation function and set the barrel angle of the tank equal to the X angle returned by the ToOrientation function. So something like this:

local x, y = CFrame.lookAt(turret_position, targeted_mouse_position):ToOrientation()
barrel_angle = x
turret_angle = y

And it works fine, but only on a flat surface (red circle is where barrel is pointing at, white circle is where it should point at):
image
However, on a 45° slope for example, it does not produce accurate results:


What can I do to make it point to the correct location? I have tried various methods such as converting the mouse position to the tank’s local space but it did not really work. Do I need more advanced math for this?

Well is there a limit on the angle of the barrel and turret, this could be what prevents it.

This isn’t the issue I believe. I can set the limits higher or lower and the same problem still occurs

Yes, that’s what you need to do.

Here’s an example:

The relevant code:

--ServoTools
local assert, atan2, deg, V0 = assert, math.atan2, math.deg, Vector3.zero

local function isNan(n: number): boolean
	return n ~= n
end

local function pointServoTo(servo: HingeConstraint, point: Vector3, pointer: Attachment?)
	assert(servo.Attachment0)
	assert(servo.Attachment1)

	local servoBaseAtt = servo.Attachment0
	local servoPointerAtt = servo.Attachment1
	local servoBaseCF = servoBaseAtt.WorldCFrame
	local pointOffset = pointer and servoBaseAtt.WorldPosition - pointer.WorldPosition or V0

	local pointRelativeToBase = servoBaseCF:PointToObjectSpace(pointOffset + point)
	local angleRelativeToBase = atan2(pointRelativeToBase.Y, -pointRelativeToBase.Z)

	local a = angleRelativeToBase
	servo.TargetAngle = isNan(a) and servo.TargetAngle or deg(a)
end

return {
	pointServoTo = pointServoTo,
}

How to use it:


local ServoTools = require(game.ReplicatedStorage.ServoTools)

local Turret = script.Parent
local Servo1 = Turret.Servo1
local Servo2 = Turret.Servo2
local MuzzleAtt = Turret:FindFirstChild("MuzzlePoint", true)
local Target = game.Workspace.Target

while wait() do
	ServoTools.pointServoTo(Servo1, Target.Position, MuzzleAtt)
	ServoTools.pointServoTo(Servo2, Target.Position, MuzzleAtt)
end
2 Likes

Well @ThanksRoBama’s idea is probably the solution as it creates the mouse position to the tank’s space, which would be a way on how to solve it because of the difference it is during a leveled ground and on a slope.

Thank you very much! I dont use HingeConstraints (I calculate the CFrames manually), so I didnt use most of the code you had written but the math inside the function really helped me.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.