i cant upload a video bc it too large, so ill explain how this turret System work(Desc + Code review) :
- Desc :
we have a TurretRing and CannonHinge
Both have 1 thing called “BTWeld” which is used to control rotation of turret(weld)
TurretRing - control y Axis of rotation
CannonHinge - control x Axis of rotation
also you might asking what are “BTWeld” welded to(into make this clear) :
BTWeld(TurretRing) : “TurretBase” which inside Chassi.Structure (body of tank)
BTWeld(CannonHinge) : “CannonRef” which inside Chassi.Turret.Structure(turret head)
reminder : (turret head != cannon)
Turret Script are running on Client sided, which player have SetNetworkOnwer to the tank(Other client can see tank turret moving while server doesnt)
the problem :
while i aiming inside tank, and then turn tank either to left or right, the aim it just doesnt lock where it aim(Only if i aiming)
- LocalScript(Turret) :
local Vehicle = script.Parent.Vehicle.Value
local DriverSeat = Vehicle.Chassi.Structure.DriverSeat.Seat
local UserInputService = game:GetService("UserInputService")
local AimPart = Vehicle.Chassi.Turret.Cannon.GunnerScope
local ViewPart = Vehicle.Chassi.Structure.DriverScope
local HorBase = Vehicle.Chassi.Turret.Structure.TurretRing
local VertBase = Vehicle.Chassi.Turret.Cannon.CannonHinge
local VertRef = Vehicle.Chassi.Turret.Structure.CannonRef
local SmokeLauncherH = Vehicle.Chassi.Structure.EngineBay.MainEngine.ESS
local SmokeLauncherT = Vehicle.Chassi.Turret.Structure.SmokeLauncher
--local FlareLauncher = Vehicle.Chassi.Turret.Structure.FlareLauncher
local event = game.ReplicatedStorage.TankGunsFolder:WaitForChild("TurretRotateEvent")
local currentAngle = VertBase.Orientation.X-VertRef.Orientation.X
local RunService = game:GetService("RunService")
local Horn = Vehicle.Chassi.Structure.EngineBay.MainEngine.Horn
local Indicator = script.Parent.DriverFrame.TankIndicator
local GunnerSeat = Vehicle.Chassi.Turret.Structure.GunnerSeat.Seat
local Player = game.Players.LocalPlayer
local mouse = Player:GetMouse()
local Camera = workspace.CurrentCamera
Camera.CameraSubject = Player.Character.Humanoid
local Aiming = false
local DriverView = false
local SensLimit = 2.3
local motorTurn = false
Indicator.Turret.Rotation = (Vehicle.Chassi.Structure.TurretBase.Orientation.Y-HorBase.Orientation.Y)
mouse.TargetFilter = Vehicle
local IsTurretAiming = script.Parent.IsTurretAiming
local IsCommTurretAiming = script.Parent.IsCommTurretAiming
-- Config
local ZoomLevel = 0
local tankModule = require(Vehicle.ModdedScript.Config)
-- Mobile Support
local function IsMobile()
return UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled
end
local MobiButtons = script.Parent.MobileButtons
local Mobile = false
-- Variables to track touch state
local currentTouch = nil
local previousTouchPosition = nil
-- Settings (adjust these as needed)
local SensLimit = 50 -- Max movement speed per frame
local BaseSensitivity = 0.07 -- How responsive the turret is
local currentsen = BaseSensitivity
local DefaultFOV = Camera.FieldOfView
local function GetBestSen(BaseSen, defaultFOV, currentFOV)
return BaseSen * (currentFOV / defaultFOV)
end
-- Crosshair
local CrosshairAim = script.Parent.Periscope.ImageLabel
local function EnterCamera()
if IsCommTurretAiming.Value then return end
Aiming = true
DriverView = false
Camera.CameraType = "Scriptable"
Camera.CFrame = AimPart.CFrame
UserInputService.MouseDeltaSensitivity = 0.03
UserInputService.MouseIconEnabled = false
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
Camera.FieldOfView = 7
script.Parent.Periscope.Visible = true
-- Addon
DriverSeat["Tank Cannon Rotating"].Playing = true
MobiButtons.ZoomButton.Visible = true
IsTurretAiming.Value = true
end
local function EnterDriverView()
Aiming = false
DriverView = true
Camera.CameraType = "Scriptable"
Camera.CFrame = ViewPart.CFrame
UserInputService.MouseIconEnabled = false
Camera.FieldOfView = 70
-- Addon
DriverSeat["Tank Cannon Rotating"].Playing = false
MobiButtons.ZoomButton.Visible = false
IsTurretAiming.Value = true
currentsen = BaseSensitivity
end
local function ExitCamera()
Aiming = false
DriverView = false
motorTurn = false
Camera.CameraType = "Custom"
Camera.FieldOfView = 70
Camera.CameraSubject = Player.Character.Humanoid
UserInputService.MouseDeltaSensitivity = 1
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
UserInputService.MouseIconEnabled = true
script.Parent.Periscope.Visible = false
-- Addon
DriverSeat["Tank Cannon Rotating"].Playing = false
MobiButtons.ZoomButton.Visible = false
IsTurretAiming.Value = false
currentsen = BaseSensitivity
end
if IsMobile() then
MobiButtons.Visible = true
Mobile = true
end
if Mobile then
MobiButtons.AimButton.MouseButton1Click:Connect(function()
if Aiming == false then
ExitCamera()
EnterCamera()
elseif Aiming == true then
ExitCamera()
ZoomLevel = 0
end
end)
MobiButtons.DriverViewButton.MouseButton1Click:Connect(function()
if DriverView == false then
ExitCamera()
EnterDriverView()
elseif DriverView == true then
ExitCamera()
end
end)
MobiButtons.ZoomButton.MouseButton1Click:Connect(function()
if not Aiming then return end
if ZoomLevel < tankModule.MaxZoomLevel then
ZoomLevel += 1
currentsen = GetBestSen(BaseSensitivity, DefaultFOV, Camera.FieldOfView)
else
ZoomLevel = 0
currentsen = BaseSensitivity
end
end)
MobiButtons.ReleaseSmoke.MouseButton1Click:Connect(function()
if SmokeLauncherH.Explosion.Enabled then return end
SmokeLauncherH.Explosion.Enabled = true
SmokeLauncherH.Smoke:Play()
task.wait(20)
SmokeLauncherH.Smoke:Stop()
SmokeLauncherH.Explosion.Enabled = false
end)
MobiButtons.LaunchSmoke.MouseButton1Click:Connect(function()
if SmokeLauncherT.Grenade.Transparency == 1 then return end
SmokeLauncherT.RemoteEvent:FireServer(SmokeLauncherT.Launcher.Attachment.WorldPosition, SmokeLauncherT.Launcher.Attachment.WorldOrientation)
end)
MobiButtons.HeadLight.MouseButton1Click:Connect(function()
Vehicle.Chassi.Structure.HeadLights.RemoteEvent:FireServer()
end)
MobiButtons.IntLight.MouseButton1Click:Connect(function()
Vehicle.Chassi.Structure.InteriorLights.RemoteEvent:FireServer()
end)
MobiButtons.Horn.InputBegan:Connect(function()
Horn.RemoteEvent:FireServer("Start")
end)
MobiButtons.Horn.InputEnded:Connect(function()
Horn.RemoteEvent:FireServer("Stop")
end)
else
UserInputService.InputBegan:connect(function(inputObject, gameProcessedEvent)
if inputObject.KeyCode == Enum.KeyCode.F and not gameProcessedEvent then
if Aiming == false then
ExitCamera()
EnterCamera()
elseif Aiming == true then
ExitCamera()
ZoomLevel = 0
end
elseif inputObject.KeyCode == Enum.KeyCode.V and not gameProcessedEvent then
if DriverView == false then
ExitCamera()
EnterDriverView()
elseif DriverView == true then
ExitCamera()
end
elseif inputObject.KeyCode == Enum.KeyCode.Z and Aiming == true and not gameProcessedEvent then
if ZoomLevel < tankModule.MaxZoomLevel then
ZoomLevel += 1
else
ZoomLevel = 0
end
elseif inputObject.KeyCode == Enum.KeyCode.C and not gameProcessedEvent then
if SmokeLauncherH.Explosion.Enabled then return end
SmokeLauncherH.Explosion.Enabled = true
SmokeLauncherH.Smoke:Play()
task.wait(20)
SmokeLauncherH.Smoke:Stop()
SmokeLauncherH.Explosion.Enabled = false
elseif inputObject.KeyCode == Enum.KeyCode.J and not gameProcessedEvent then
if SmokeLauncherT.Grenade.Transparency == 1 then return end
SmokeLauncherT.RemoteEvent:FireServer(SmokeLauncherT.Launcher.Attachment.WorldPosition, SmokeLauncherT.Launcher.Attachment.WorldOrientation)
--[[elseif inputObject.KeyCode == Enum.KeyCode.J and not gameProcessedEvent then
if FlareLauncher.Grenade.Transparency == 0 then
FlareLauncher.Grenade.Transparency = 1
FlareLauncher.RemoteEvent:FireServer(FlareLauncher.Launcher.Attachment.WorldPosition,FlareLauncher.Launcher.Attachment.WorldOrientation)
end
]]
elseif inputObject.KeyCode == Enum.KeyCode.L and not gameProcessedEvent then
Vehicle.Chassi.Structure.HeadLights.RemoteEvent:FireServer()
elseif inputObject.KeyCode == Enum.KeyCode.K and not gameProcessedEvent then
Vehicle.Chassi.Structure.InteriorLights.RemoteEvent:FireServer()
elseif inputObject.KeyCode == Enum.KeyCode.H and not gameProcessedEvent then
Horn.RemoteEvent:FireServer("Start")
end
end)
UserInputService.InputEnded:connect(function(inputObject, gameProcessedEvent)
if inputObject.KeyCode == Enum.KeyCode.H and not gameProcessedEvent then
Horn.RemoteEvent:FireServer("Stop")
end
end)
end
local function MoveTurretPC()
if Aiming then
Camera.CameraType = "Scriptable"
Camera.FieldOfView = tankModule.ZoomLevelTable[ZoomLevel]
UserInputService.MouseDeltaSensitivity = 0.03
currentAngle = VertBase.Orientation.X-VertRef.Orientation.X
if motorTurn == true then
local position = Vector2.new(mouse.X, mouse.Y)
local size = Vector2.new(mouse.ViewSizeX, mouse.ViewSizeY)
local normalizedPosition = position / size
if normalizedPosition.X < 0.45 then
HorBase.BTWeld.C0 = HorBase.BTWeld.C0 * CFrame.Angles(math.rad((1-normalizedPosition.X)/2.8),0,0)
elseif normalizedPosition.X > 0.55 then
HorBase.BTWeld.C0 = HorBase.BTWeld.C0 * CFrame.Angles(math.rad(-normalizedPosition.X/2.8),0,0)
end
elseif motorTurn == false then
local delta = UserInputService:GetMouseDelta()
local deltaX = delta.X
local deltaY = delta.Y
if delta.X > SensLimit then
deltaX = SensLimit
elseif delta.X < -SensLimit then
deltaX = -SensLimit
end
if delta.Y > SensLimit then
deltaY = SensLimit
elseif delta.Y < -SensLimit then
deltaY = -SensLimit
end
if currentAngle > 0 then
if currentAngle-deltaY > 13 then
deltaY = 0
end
elseif currentAngle < 0 then
if currentAngle-deltaY < -5 then
deltaY = 0
end
end
--if not HorBase.BTWeld then return end
HorBase.BTWeld.C0 = HorBase.BTWeld.C0 * CFrame.Angles(math.rad(-deltaX),0,0) -- This line is where rotation applied
VertBase.BTWeld.C0 = VertBase.BTWeld.C0 * CFrame.Angles(math.rad(deltaY/2),0,0) -- This line is where rotation applied
end
event:FireServer(HorBase,VertBase,HorBase.BTWeld.C0,VertBase.BTWeld.C0) -- Optional(you can comment this out)
Camera.CFrame = AimPart.CFrame
Indicator.Turret.Rotation = (Vehicle.Chassi.Structure.TurretBase.Orientation.Y-HorBase.Orientation.Y)
--print((AimPart.Position-mouse.hit.p).Magnitude)
elseif DriverView then
Camera.CameraType = "Scriptable"
Camera.CFrame = ViewPart.CFrame
else
Camera.CameraType = "Custom"
Camera.CameraSubject = Player.Character.Humanoid
end
end
-- [ Mobile Support Parts ] --
-- Set up touch event listeners
if Mobile then
UserInputService.TouchStarted:Connect(function(touch)
if not Aiming then return end
currentTouch = touch
previousTouchPosition = touch.Position
end)
UserInputService.TouchEnded:Connect(function(touch)
if not Aiming then return end
currentTouch = nil
previousTouchPosition = nil
end)
UserInputService.TouchMoved:Connect(function(touch)
if not Aiming then return end
if currentTouch ~= touch then return end
currentTouch = touch
end)
end
-- allat Mobile
local function MoveTurretMobile()
if Aiming then
Camera.CameraType = "Scriptable"
Camera.FieldOfView = tankModule.ZoomLevelTable[ZoomLevel]
currentAngle = VertBase.Orientation.X - VertRef.Orientation.X
if currentTouch then
local currentPosition = currentTouch.Position
if previousTouchPosition then
-- Calculate movement delta :P
local delta = (currentPosition - previousTouchPosition) * currentsen
local deltaX = math.clamp(delta.X, -SensLimit, SensLimit)
local deltaY = math.clamp(delta.Y, -SensLimit, SensLimit)
-- Limit vertical movement based on current angle yo turret
if currentAngle > 0 and currentAngle - deltaY > 13 then
deltaY = 0
elseif currentAngle < 0 and currentAngle - deltaY < -5 then
deltaY = 0
end
-- Move the turret
HorBase.BTWeld.C0 = HorBase.BTWeld.C0 * CFrame.Angles(math.rad(-deltaX), 0, 0)
VertBase.BTWeld.C0 = VertBase.BTWeld.C0 * CFrame.Angles(math.rad(deltaY), 0, 0)
end
previousTouchPosition = currentPosition
else
previousTouchPosition = nil
end
event:FireServer(HorBase, VertBase, HorBase.BTWeld.C0, VertBase.BTWeld.C0)
Camera.CFrame = AimPart.CFrame
Indicator.Turret.Rotation = (Vehicle.Chassi.Structure.TurretBase.Orientation.Y - HorBase.Orientation.Y)
elseif DriverView then
Camera.CameraType = "Scriptable"
Camera.CFrame = ViewPart.CFrame
else
Camera.CameraType = "Custom"
Camera.CameraSubject = Player.Character.Humanoid
end
end
if Mobile then
RunService.RenderStepped:Connect(MoveTurretMobile)
else
RunService.RenderStepped:Connect(MoveTurretPC)
end
DriverSeat.Changed:connect(function(property)
if property ~= 'Occupant' then return end
local occupant = DriverSeat.Occupant
if not occupant then
ExitCamera()
Horn.RemoteEvent:FireServer("Stop")
script.Parent.GuiRemover.RemoveEvent:FireServer()
end
end)
mouse.Button2Down:Connect(function()
if Aiming == true then
motorTurn = true
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
UserInputService.MouseIconEnabled = true
end
end)
mouse.Button2Up:Connect(function()
if Aiming == true then
motorTurn = false
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
UserInputService.MouseIconEnabled = false
end
end)
--Made by Ferrarico
-- Modded by Mawin_CK
im very thankful if you helped me out with this