How to make a tank in roblox studio

A simple tank game for people who love tanks and fast paced gameplay.

How to make a tank in roblox studio

Step 0 - Setting up in Linux

Because I switched over to Linux from Windows (I use Lubuntu btw.), I needed to find a way to use Roblox Studio without a virtual machine. It took awhile to get Wine to work, because I skipped a crucial error during installation, but it worked out in the end.

In the meantime I was setting up my GitHub repository with VS Code, Rojo, and roblox-ts. These are amazing tools, and I recommend learning them if you are considering improving your scripting skill set.

Step 1 - How do I tank?

I REALLY wanted to make a good tank, so I stole like an artist, took a look at this script, and made it my own. I couldn’t get roblox’s built in screen recorder to work on Linux, so I installed OBS.

How to make a tank in roblox studio
How to make deforming vehicle tracks Community Tutorials

Introduction I recently wrote up a private message to another DevForum user that contained basically this same tutorial about how to make working vehicle tracks (think like on a tank) that deform with terrain. I thought I would publicly share it here too since I’ve only seen a few other people do it. The method I’m about to share should end up looking like the tracks in Armored Patrol. There are probably multiple ways to go about doing this, but this is what works for me. Suspension Setup The…

I disabled players’ characters from loading in through Players.CharacterAutoLoads = false; in my server script and linked player controls and camera to the tank spawned in whenever a player is added.

Using Rojo for Remotes

I created a remotes.model.json file in my rojo project and linked it in my default.project.json with the following:

default.project.json

"ReplicatedStorage": { "$className": "ReplicatedStorage", "rbxts_include": { "$path": "include", "node_modules": { "$path": "node_modules/@rbxts" } }, "Remotes": { "$path": "remotes.model.json" }, "TS": { "$path": "out/shared" } },

remotes.model.json

{ "ClassName": "Folder", "Children": [ { "Name": "LinkTank", "ClassName": "RemoteEvent" } ] }

Controls

After linking the player and tank, I created a third person camera and added some simple controls.

//devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/4X/8/7/f/87fa13401e050d1598a2002edd9a57de9f0af8fd.mp4

Improving the Model

I added more wheels and added a turrent on top. I kept this turrent in place by adjusting its CFrame every frame, but because the client lags behind when syncing physical bodies, I get this effect.

//devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/4X/9/0/d/90d90ea486d61862e7ae1c515ded39830da629c2.mp4

I decided to weld it instead, but due to the laws of physics. The tank is now unbalanced.

How to make a tank in roblox studio

But if I make the turret mass-less, it’s fixed.
How to make a tank in roblox studio

Here’s another video, running out of time

//devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/4X/1/f/9/1f9baa588753d0b294a5498a948d3b418a07dfe4.mp4

How to make a tank in roblox studio
Roblox

How to make a tank in roblox studio

Check out Just Tanks - IN DEV. It’s one of the millions of unique, user-generated 3D experiences created on Roblox. Be sure to follow up on my daily devlogs @ 9 EST on devforum.

I’m open to critiques, not dislikes, and want to know how you feel about this game. I’ll post daily devlogs @ 9 EST here on devforum.

Thanks for reading (or skipping).

Oh, if your tank flips exit and join back in. I ran out of time to implement a respawn / flip system.

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:

How to make a tank in roblox studio

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