How do I improve this tank I'm creating?

Since ROBLOX updated the constraints (especially for Hinges), I’ve been pretty confused on how to do them.

I’m working on this tank model:

So far, I was able to make its turret move around with a turret I use in one of my other games, 2 Player Military Tycoon.

This is how it functions:
https://gyazo.com/ba7a556b1e8dc7282d838ec2ea28422a
https://gyazo.com/f4aaa94abfb85718837fea2a74623490

However, as you can see, there’s a few issues with the turret’s movement:

  1. The turret seems to be higher than it should be, giving it a weird look. This might be a problem with the modeling of the tank itself.
  2. The movement of the turret is wonky; the turret itself and the main gun appear to move around off center, making it look unsymmetrical.

I got the turret to work via using the basic ROBLOX constraints plugin in studio; I did not use any scripting for this, but I’d bet this would perform much better with some sort of programming involved. How would I do this?

Relevant scripts for this model

Regen Button

model = script.Parent.Parent
backup = model:clone()
enabled = true
function regenerate()
	model:Destroy()
	wait(1)
	model = backup:clone()
	local PrimaryInModel = model["M1Abrams"].Body
	local PartsOfModel = model["M1Abrams"]:GetDescendants()
	for k = 1,#PartsOfModel do
		if PartsOfModel[k]:IsA("Part") or PartsOfModel[k]:IsA("WedgePart") or PartsOfModel[k]:IsA("MeshPart") then
			if PartsOfModel[k].Name ~= "MainGun" and PartsOfModel[k].Name ~= "Turret" then
				if not PartsOfModel[k]:FindFirstAncestor("Device") then
					if PartsOfModel[k]:FindFirstAncestor("Gun") then
						local weld = Instance.new("WeldConstraint")
						weld.Part0 = PrimaryInModel
						weld.Part1 = PartsOfModel[k]
						weld.Parent = model["M1Abrams"].Turret
					end
					local weld = Instance.new("WeldConstraint")
					weld.Part0 = PrimaryInModel
					weld.Part1 = PartsOfModel[k]
					weld.Parent = PrimaryInModel
				end
			end	
		end
	end
	model.Parent = game.Workspace
	script.Disabled = true
	wait(2)
	script.Disabled = false
end
function onHit(hit)
	if (hit.Parent:FindFirstChild("Humanoid") ~= nil) and enabled then
		regenerate()
	end
end
script.Parent.Touched:connect(onHit)

Local Turret Movement Script

local Vehicle = script:WaitForChild("Vehicle")
local Turret
repeat
	wait()
	Turret = Vehicle.Value
until
Turret
local Device = Turret:WaitForChild("Device")
local Seat = Device:WaitForChild("Seat")
local Fire = Seat:WaitForChild("Fire")
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local Character = Player.Character or Player.CharacterAdded:wait()
local Weapon = Device:WaitForChild("Weapon")
local GyroPart = Weapon:WaitForChild("Gyro")
local BodyGyro = GyroPart:WaitForChild("BodyGyro")
local Firing = false

Mouse.Icon = "rbxassetid://139669907"

Mouse.Button1Down:connect(function()
	if not Firing then
		Firing = true
		Fire:InvokeServer("StartShooting")
	end
end)

Mouse.Button1Up:connect(function()
	if Firing then
		Firing = false
		Fire:InvokeServer("StopShooting")
	end
end)

Mouse.Move:Connect(function()
	if Vehicle.Value and Weapon:FindFirstChild("Gyro") then
		Fire:InvokeServer("u_better_move",BodyGyro,Mouse.hit)
	end	
end)

Mouse.Icon = ""

Server Tank Movement Script

local Seat = script.Parent
local Device = Seat.Parent
local Fire = Seat:WaitForChild("Fire")
local LocalTurret = script:WaitForChild("LocalTurret")
local ExplosionSound = script:WaitForChild("Explosion")
local Weapon = Device:WaitForChild("Weapon")
local Gun1 = Weapon:WaitForChild("Gun1")
--local Gun2 = Weapon:WaitForChild("Gun2")
local Gun1Fire = Gun1:WaitForChild("Fire")
--local Gun2Fire = Gun2:WaitForChild("Fire")
local AntiAirTurret = Device.Parent
local ColorDescendantModels = {"Color";"Chassis"}
local AttackingDamage = 100
local TimeBetweenShots = .5
local MaxBulletDist = 1000
local Debounce = false
local Firing = false

Seat:GetPropertyChangedSignal("Occupant"):connect(function()
	local Humanoid = Seat.Occupant
	local Char = Humanoid and Humanoid.Parent
	local Player = Char and game.Players:GetPlayerFromCharacter(Char)
	if Player then
		for _,Name in pairs(ColorDescendantModels)do
			local FindDescendant = AntiAirTurret:FindFirstChild(Name,true)
			for _,Part in pairs(FindDescendant and FindDescendant:GetChildren() or {})do
			    if Part:IsA("BasePart")then
					Part.BrickColor = Player.TeamColor
				end
			end
		end
		local ClonedLocalTurret = LocalTurret:clone()
		local VehicleValue = ClonedLocalTurret:WaitForChild("Vehicle")
		VehicleValue.Value = AntiAirTurret
		ClonedLocalTurret.Parent = Char
		repeat
			game["Run Service"].Heartbeat:wait()
		until
		not Seat.Occupant or (not Weapon:FindFirstChild("Gun1"))
		VehicleValue.Value = nil
		ClonedLocalTurret:Destroy()
	end
end)

function AddKill(Player)
	local Leaderstats = Player and Player:FindFirstChild("leaderstats")
	local KOs = Leaderstats and Leaderstats:FindFirstChild("KOs")
	if KOs then
		KOs.Value = KOs.Value+1
	end
end

function DoDamage(Player,Part,AttackingDamage)
	local Char = Part and Part.Parent
	local Humanoid = Char and Char:FindFirstChild("Humanoid")
	local ArmourValue = Char and Char:FindFirstChild("ArmourValue")
	local Armour = ArmourValue and ArmourValue.Value
	local ArmourDamage = Armour and AttackingDamage or 0
	if Armour then
		ArmourDamage = math.clamp(math.ceil(ArmourDamage*.66),0,Armour)
		ArmourValue.Value = Armour-ArmourDamage
	end
	if Humanoid and Humanoid ~= Seat.Occupant and Humanoid.Health > 0 and AttackingDamage then
		local HumanoidDamage = AttackingDamage-ArmourDamage
		Humanoid:TakeDamage(HumanoidDamage)
		if Humanoid.Health <= 0 then
			AddKill(Player)
		end
	end
end

function FireBullet(Shoot,Player)
	if Shoot then
		local FromPosition = Shoot.Position --+Shoot.Velocity*-Shoot.RotVelocity --(Shoot.CFrame*CFrame.new(0,0,-Shoot.Size.Z)).Position --Shoot.Position
		local ToPosition = (Shoot.CFrame*CFrame.new(0,0,-MaxBulletDist)).Position
		local Part,Position,Normal = game.Workspace:FindPartOnRay(Ray.new(FromPosition,(ToPosition-FromPosition).Unit*MaxBulletDist),AntiAirTurret)
		local Dist = (Position-FromPosition).Magnitude
		local Laser = Shoot:FindFirstChild("Laser") or Instance.new("Beam",Shoot) --Instance.new("Part",game.Workspace)
		local Name = ((Player and Player).Name or "Unknown").."Shoot"
		local A0 = Shoot:FindFirstChild("Shoot") or Instance.new("Attachment",Shoot)
		local A1 = game.Workspace.Terrain:FindFirstChild(Name) or Instance.new("Attachment",game.Workspace.Terrain)
		Laser.Name = "Laser"
		A0.Name = "Shoot"
		A1.Name = Name
		A1.WorldPosition = Position or ToPosition
		Laser.FaceCamera = true
		Laser.Color = ColorSequence.new(Color3.fromRGB(239,184,56)) --Color3.fromRGB(239,184,56)
		Laser.Width0 = .5
		Laser.Width1 = .5
		Laser.Attachment0 = A0
		Laser.Attachment1 = A1
		Laser.Enabled = true
		if Part then
			Part:BreakJoints()
			local Explosion = Instance.new("Explosion")
			Explosion.ExplosionType = "NoCraters"
			Explosion.Position = Position
			Explosion.BlastRadius = 8
			Explosion.BlastPressure = 125000
			Explosion.Parent = game.Workspace
			local Cloned = ExplosionSound:clone()
			Cloned.Parent = Part
			Cloned.PlayOnRemove = true
			Cloned:Destroy()
			local PartP = Part.Parent
			local PartPP = PartP and PartP.Parent
			local HitParts = PartPP and PartPP:FindFirstChild("Parts")
			local Engine = HitParts and HitParts:FindFirstChild("Engine")
			local BodyGyro = Engine and Engine:FindFirstChild("BodyGyro")
			if BodyGyro then
				BodyGyro:Destroy()
			end
			DoDamage(Player,Part,AttackingDamage)
		end
		return Laser
	end
end

Fire.OnServerInvoke = function(Player,DoFunction, gyro, targ)
	if DoFunction == "StartShooting" then
		Firing = true
		while Firing and not Debounce do
			Debounce = true
			local Laser1
			local Laser2
			if Weapon:FindFirstChild("Gun1")then --FindFirstChild is just in case they get destroyed.
				Gun1Fire:Play()
				Laser1 = FireBullet(Gun1,Player)
			end
			--if Weapon:FindFirstChild("Gun2")then
				--Gun2Fire:Play()
			--	Laser2 = FireBullet(Gun2,Player)
		--	end
			wait(.1)
			if Laser1 then
				Laser1.Enabled = false
			end
			if Laser2 then
				Laser2.Enabled = false
			end
			wait(TimeBetweenShots)
			Debounce = false
		end
	elseif DoFunction == "StopShooting" then
		Firing = false
	elseif DoFunction == "u_better_move" and gyro and targ then
		gyro.CFrame = targ
		print(gyro.CFrame)
		print(targ)
	end
end
3 Likes

You could shorten this with basic metatable scripting as it is reusable and easy to debug/add too later on. But I would say modulate the code I you can. that would make things a lot neater and nicer to look at.

I’m not entirely concerned with the neatness of the code right now, I need to make its mobility far more smooth. Right now it’s very… un-aesthetically pleasing.