How to Make a Plane
| This is an Advanced, Building & Lua related tutorial. |
Introduction
This tutorial will guide you through the steps needed to create a simple plane from scratch. It will then show you how to add the different features of airplanes, such as shooting, exploding when crashing, and customizing the look of your plane.
Creating a Plane From Scratch
The plane will consist of these models: Hangar, Plane, BodyKit, Parts. We will start first by creating the Hangar model.
Creating the Hangar for the Plane
The hangar for the plane is used to hold the plane safely off the ground. It also makes it easier to climb aboard and easier to take off.
In this example, we are using the simplest hangar: two bricks in the shapes of low walls - on which the wings of the plane will rest. NOTE: Add steps to the back of the hangar so you can climb up.
Follow these steps in GoodBlox Studio to create the Hangar:
– With the Workspace selected in the Explorer window, Select Insert > Object and select Model from the pop up window.
– Name this model Hangar in the Explorer window.
– Insert an object into Hangar of type IntValue, name it Regen.
– Insert an object of type Part into Hangar and name it Base1. This brick will be one of the low walls to support the plane.
- Enlarge it, so it looks like a short small wall. - Change the Top Surface to "Smooth" so the plane will not stick to it. – In the properties for this part, click “Anchored” – so it won’t move.
– Copy and paste Base1 and rename the new brick Base2.
– Drag this brick to be under the Hangar model. – Move this brick to be next to Base1, remember to leave enough room for your plane to sit on top of these two walls.
Creating the Plane Model
In this section we will create the basic pieces that are needed to make a vehicle fly. Remember, the scripts will expect the critical 'engine' bricks to be named as shown in this tutorial. If you want to change a name, you will have to change the old name in the scripts to the new name.
– Inside Hangar, insert a Model and name it Plane.
– Inside Plane model, insert another model and name it BodyKit. BodyKit is where you can keep all the decorative pieces of the plane, without getting mixed up with the 'engine' pieces.
– Inside Plane model, insert another model and name it Parts. Parts is the model that will hold the pieces of the plane which makes it fly.
– Inside Plane, insert an object of type IntValue, name it PlaneCheck.
– Inside Plane, add another IntValue, name it Stunt.
Creating the Parts Model
For the following section, we will add all the critical pieces to the model called Parts:
- Inside Parts model, insert object CFrameValue and name it “OriginCFrame”.
- Add about 30 of them, all named the same.
– Inside Parts, insert object Seat.
- Make sure the Front Surface of the Seat is facing towards the front of the plane. You can change
the type of the FrontSurface property to hinge, to make sure you know which is the FrontSurface,
and that it is indeed pointing forward. Return the property to smooth. - Change the property formFactor to plate - to make it thin like other seats. - Set the size to (2,0.4,2) - a small seat. A large seat could cause your plane not to fly. - Change the TopSurface to Weld - In our example, we made the seat Bright blue Brick Color.
– Inside Parts, insert object Part and name it Engine.
- Make sure the Front Surface of the Engine is facing towards the front of the plane. - Change the size of the brick to 6, 1.2, 12. - In our example, we made the engine brick Bright red Brick Color. - Change the Top Surface to "Weld"
– Inside Parts, add a Part object and name it Gun1.
- Change the Front Surface to “Hinge”. Make sure it is facing forward. - Change the size so it is 3, 1.2, 1. - In our example, we made the guns Black Brick color. - Change the Back Surface to "Weld"
– Inside Parts, add a Part object and name it Gun2.
- Change the Front Surface to “Hinge”. Make sure it is facing forward. - Change the size so it is 3, 1.2, 1 - In our example, we made the guns Black Brick color. - Change the Back Surface to "Weld"
– Inside Parts, add a Part object and name it Tip.
- Make sure the Front surface is pointing forward - Change the size to 2, 1.2, 2 - In our example, we made the tip Bright yellow Brick color. - Change the Back Surface to "Weld"
– Inside Engine, add an IntValue, and name it Count.
Putting the plane together
– Move the Seat on top of the Engine.
– Add the Tip to the front of the Engine.
– You can add more bricks to the sides of the Engine to make wings.
- Make sure to place these additional bricks in the Parts model. - Make sure the wings are welded to the engine, but don't have the bottom surface set to weld.
– Attach a gun to each wing – making sure the hinge points forward.
– Move this Plane model to the top of the Hangar.
– Make sure the airplane is not attached or welded to the base pieces.
- Save your work to a file.
- Test in Solo mode to make sure the plane hangs together in one piece!
Script to Regenerate the Plane Model
If the engine brick is touched, it will regenerate the plane.
- Inside Engine, add a Script. Add this code to the script:
model = script.Parent.Parent.Parent -- Get the plane model - Engine.Parts.Plane backup = model:clone() -- Copy the plane local debounce = false function onTouch(part) if (part.Name == "Safe") and (debounce == false) and (script.Parent.Count.Value == 0) then debounce = true wait(2) model = backup:clone() -- Clone the copy of the plane model.Parent = game.Workspace -- regens the plane? model:makeJoints() script.Parent.Count.Value = 1 debounce = false end end script.Parent.Touched:connect(onTouch) -- If the engine piece is touched
The Flying Script
- Inside Engine, insert an object BodyGyro.
- Inside Engine, insert an object BodyPosition.
- Inside StarterPack, insert object HopperBin – name it Plane.
- Inside Plane HopperBin (NOT the model called "Plane"), insert object Script, and name it PlaneFlyer. Add this code to the script:
bin=script.Parent
plane=nil
hold=false
local debounce = false
local planedebounce = false
local stuntdebounce = false
local controlling = false
function fire(pln,spn)
local missile = bin.Rocket:clone()
missile.CFrame = spn.CFrame * CFrame.new(0, 0, -35)
missile.RocketScript.Disabled = false
missile.Parent = game.Workspace
local creator_tag = Instance.new("ObjectValue")
creator_tag.Value = game.Players.LocalPlayer
creator_tag.Name = "creator"
creator_tag.Parent = missile
missile.Owner.Value = pln
end
function computeDirection(vec)
local lenSquared = vec.magnitude * vec.magnitude
local invSqrt = 1 / math.sqrt(lenSquared)
return Vector3.new(vec.x * invSqrt, vec.y * invSqrt, vec.z * invSqrt)
end
function move(target, engine)
local origincframe = engine:findFirstChild("BodyGyro").cframe
local dir = (target - engine.Position).unit
local spawnPos = engine.Position
local pos = spawnPos + (dir * 1)
engine:findFirstChild("BodyGyro").maxTorque = Vector3.new(9000, 9000, 9000)
engine:findFirstChild("BodyGyro").cframe = CFrame.new(pos, pos + dir)
wait(0.1)
engine:findFirstChild("BodyGyro").maxTorque = Vector3.new(0, 0, 0)
engine:findFirstChild("BodyGyro").cframe = origincframe
end
function findPlane(player)
local list = player.Character:GetChildren()
for x = 1, #list do
if (list[x].Name == "Plane") then
local weld = list[x]:FindFirstChild("Parts"):FindFirstChild("Seat"):FindFirstChild("SeatWeld")
if (weld ~= nil) and (weld.Part1 == player.Character:FindFirstChild("Torso")) then
return list[x]
end
end
end
return nil
end
function onButton1Down(mouse)
local vehicle = findPlane(script.Parent.Parent.Parent)
if vehicle ~= nil and debounce == false and planedebounce == false then
debounce = true
controlling = true
while true do
wait()
local engine = vehicle.Parts.Engine
local position = mouse.Hit
local target = position.p
if engine:findFirstChild("FlyScript") ~= nil then
move(target, engine)
end
if planedebounce == true or
controlling == false then break end
end
wait(.1)
debounce = false
end
end
function onButton1Up(mouse)
controlling = false
end
function onSelected(mouse)
mouse.Icon = "rbxasset://textures\\GunCursor.png"
mouse.Button1Down:connect(function() onButton1Down(mouse) end)
mouse.Button1Up:connect(function() onButton1Up(mouse) end)
mouse.KeyDown:connect(onKeyDown)
end
function onKeyDown(key)
if (key~=nil) then
key = key:lower()
local vehicle = findPlane(script.Parent.Parent.Parent)
if (vehicle==nil) then return end
plane = vehicle.Parts
local engine = vehicle.Parts.Engine
if (key=="f") and (bin.Reload.Value == 0) then
fire(vehicle,plane.Gun1)
fire(vehicle,plane.Gun2)
bin.Reload.Value = 1
wait(1)
bin.Reload.Value = 0
end
if (key=="x") and planedebounce == false then
local power = plane.Engine:findFirstChild("FlyScript")
if (power ~= nil) then
power:remove()
end
end
if (key=="y") then
local power = plane.Engine:findFirstChild("FlyScript")
if (power ~= nil) then return end
local fly = script.FlyScript:clone()
fly.Disabled = false
fly.Parent = plane.Engine
end
if (key=="k") and planedebounce == false then
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y -0.7, 0)
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y -0.7, 0)
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y -0.7, 0)
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y -0.7, 0)
end
if (key=="h") and planedebounce == false then
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y +0.7, 0)
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y +0.7, 0)
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y +0.7, 0)
wait()
engine.RotVelocity = Vector3.new(0, engine.RotVelocity.y +0.7, 0)
return end
if (key=="j") and planedebounce == false then
local body = plane.Engine.BodyGyro
body.maxTorque = Vector3.new(9000, 9000, 9000)
local position = engine.CFrame * Vector3.new(0, 0.5, -4)
local dir = position - engine.Position
dir = computeDirection(dir)
local spawnPos = engine.Position
local pos = spawnPos + (dir * 8)
body.cframe = CFrame.new(pos, pos + dir)
wait(.2)
body.maxTorque = Vector3.new(0, 0, 0)
end
if (key=="l") and planedebounce == false then
local body = plane.Engine.BodyGyro
body.maxTorque = Vector3.new(9000, 0, 0)
local frame = plane:FindFirstChild("OriginCFrame")
if frame ~= nil then
body.cframe = frame.Value
end
wait(0.1)
body.maxTorque = Vector3.new(0, 0, 0)
end
if (key=="u") and planedebounce == false then
local body = plane.Engine.BodyGyro
body.maxTorque = Vector3.new(9000, 9000, 9000)
local position = engine.CFrame * Vector3.new(0, -0.5, -4)
local dir = position - engine.Position
dir = computeDirection(dir)
local spawnPos = engine.Position
local pos = spawnPos + (dir * 8)
body.cframe = CFrame.new(pos, pos + dir)
wait(.2)
body.maxTorque = Vector3.new(0, 0, 0)
end
if (key=="g") and planedebounce == false and stuntdebounce == false then
planedebounce = true
stuntdebounce = true
plane.Parent.Stunt.Value = 1
local body = plane.Engine.BodyGyro
body.maxTorque = Vector3.new(9000, 9000, 9000)
local currentframe = plane.Engine.CFrame
for i = 1,6 do
body.cframe = plane.Engine.CFrame * CFrame.fromEulerAnglesXYZ(0, 0, 30)
wait(.2)
end
body.cframe = currentframe
wait(.6)
body.maxTorque = Vector3.new(0, 0, 0)
planedebounce = false
plane.Parent.Stunt.Value = 0
wait(3)
stuntdebounce = false
end
if (key=="t") and planedebounce == false and stuntdebounce == false then
planedebounce = true
stuntdebounce = true
plane.Parent.Stunt.Value = 1
local body = plane.Engine.BodyGyro
body.maxTorque = Vector3.new(9000, 9000, 9000)
local currentframe = plane.Engine.CFrame
local valy = 30
local valz = 30
for i = 1,8 do
body.cframe = currentframe * CFrame.fromEulerAnglesXYZ(0, valy, valz)
valy = valy +50
valz = valz +100
wait(.1)
end
body.cframe = currentframe * CFrame.fromEulerAnglesXYZ(0, 600, 0)
wait(.5)
body.maxTorque = Vector3.new(0, 0, 0)
planedebounce = false
plane.Parent.Stunt.Value = 0
wait(4)
stuntdebounce = false
end
end
end
bin.Selected:connect(onSelected)
- Inside PlaneFlyer, insert object Script, and name it FlyScript. Make this script Disabled. (The PlaneFlyer script will activate it when needed.)
Add this code to it:
local engine = script.Parent.Parent.Engine local spd = 3 local position = engine.Position while true do wait(.1) direction = engine.CFrame.lookVector position = position + spd*3*direction error = position - engine.Position engine.Velocity = spd*error engine.RotVelocity = Vector3.new(0, 0, 0) end
Adding Guns
This section describes what you need to do to add fire power to your plane.
- Inside Plane HopperBin, insert IntValue, and name it Reload
- Inside Plane HopperBin, insert object Part, and name it Rocket
- Change the shape and size of this brick to the look you want for your bullets - For example, make it size 1x1 - Change brick color to Bright red - Change Shape to Ball
- Inside Rocket, insert object Sound, name it Explosion
- Add this to SoundID property: rbxasset://sounds\collide.wav
- Inside Rocket, insert object Sound, name it Swoosh
- Add this to SoundID property: rbxasset://sounds\Rocket whoosh 01.wav
- Inside Rocket, insert ObjectValue, name it Owner
- Inside Rocket, insert script, name it RocketScript. Make this script Disabled. The PlaneFlyer script will activate it when the player gets on the plane. Add this code to the script:
r = game:service("RunService")
shaft = script.Parent
position = shaft.Position
function fly()
direction = shaft.CFrame.lookVector
position = position + 35*direction
error = position - shaft.Position
shaft.Velocity = 5*error
end
function blow()
swoosh:stop()
explosion = Instance.new("Explosion")
explosion.Position = shaft.Position
explosion.BlastRadius = 10
-- find instigator tag
local creator = script.Parent:findFirstChild("creator")
if creator ~= nil then
explosion.Hit:connect(function(part, distance) onPlayerBlownUp(part, distance, creator) end)
end
explosion.Parent = game.Workspace
connection:disconnect()
wait(.1)
shaft:remove()
end
function onTouch(hit)
if hit.Name == "Building" or
hit.Name == "Safe" then
swoosh:stop()
shaft:remove()
return end
local parent = hit.Parent.Parent
local owner = shaft.Owner
if owner ~= nil then
if parent ~= nil and owner.Value ~= nil then
if parent ~= owner.Value then
local stunt = parent:FindFirstChild("Stunt")
if stunt ~= nil then
if stunt.Value ~= 1 then
blow()
end
else
blow()
end
end
end
end
end
function onPlayerBlownUp(part, distance, creator)
if part.Name == "Head" then
local humanoid = part.Parent:findFirstChild("Humanoid")
tagHumanoid(humanoid, creator)
end
end
function tagHumanoid(humanoid, creator)
if creator ~= nil then
local new_tag = creator:clone()
new_tag.Parent = humanoid
end
end
function untagHumanoid(humanoid)
if humanoid ~= nil then
local tag = humanoid:findFirstChild("creator")
if tag ~= nil then
tag.Parent = nil
end
end
end
t, s = r.Stepped:wait()
swoosh = script.Parent.Swoosh
swoosh:play()
d = t + 4.0 - s
connection = shaft.Touched:connect(onTouch)
while t < d do
fly()
t = r.Stepped:wait()
end
-- at max range
script.Parent.Explosion.PlayOnRemove = false
swoosh:stop()
shaft:remove()
Making the Plane Explode on Impact
This script inside of the Plane model will cause the plane to explode when the Tip brick is touched.
– Inside Plane model, insert a Script object. Add this code into that script:
local boom = false
function createExplosion(position)
explosion = Instance.new("Explosion")
explosion.Position = position
explosion.BlastRadius = 12
explosion.Parent = game.Workspace
end
function onTouch(part)
if boom == true then
return
end
if (part.Name == "Rocket") or (part.Name == "Safe") or
(part.Parent.Parent.Parent == script.Parent) or
(part.Parent:findFirstChild("Humanoid")) then
return
end
if (script.Parent.Parts.Tip.Velocity.x > 50) or
(script.Parent.Parts.Tip.Velocity.x < -50) or
(script.Parent.Parts.Tip.Velocity.z > 50) or
(script.Parent.Parts.Tip.Velocity.z < -50) then
boom = true
createExplosion(script.Parent.Parts.Engine.Position)
script.Parent:BreakJoints()
local stuff = script.Parent:children()
for i=1,#stuff do
if stuff[i].Name == "BodyKit" or
stuff[i].Name == "Parts" then
local parts = stuff[i]:children()
for p = 1, #parts do
if parts[p].className == "Part" then
local velo = Instance.new("BodyVelocity")
velo.maxForce = Vector3.new(9.9e+036, 9.9e+036, 9.9e+036)
velo.velocity = Vector3.new(math.random(-15,15),
math.random(-15,15),
math.random(-15,15))
velo.Parent = parts[p]
end
end
end
end
wait(4)
script.Parent:remove()
end
end
script.Parent.Parts.Tip.Touched:connect(onTouch)
Regenerating the Plane
This section will add the scripts which will regenerate the plane after one flies off the hangar.
Inside Parts model, insert a Script. This script checks to see if the plane is away from the hangar, and changes the regen value. Add this code to that script:
position = script.Parent.Engine.Position
local object = Instance.new("ObjectValue")
object.Value = script.Parent.Parent.Parent -- Hangar model
seat = script.Parent.Seat
function onChildAdded(part)
if part.className == "Weld" then
local torso = part.Part1
if torso ~= nil then
local parent = torso.Parent
if parent ~= nil then
script.Parent.Parent.Parent = parent
while true do
wait(2)
local pos = script.Parent.Engine.Position
if (position - pos).magnitude > 30 then
if object.Value ~= nil then
object.Value.Regen.Value = 1
wait(.5)
object.Value.Regen.Value = 0
object.Value = nil
end
break
end
end
while true do
print("Loop")
wait(2)
if part == nil then
script.Parent.Parent.Parent = game.Workspace
script.Parent.Parent:MakeJoints()
break end
end
end
end
end
end
seat.ChildAdded:connect(onChildAdded)
– Insert a Script object into Hangar model. This script actually creates the new plane when the Regen value changes. Add this code to the script:
system = script.Parent -- gets the Hangar model
model = system.Plane -- gets the Plane model
backup = model:Clone() -- creates a copy of the Plane model
regen = system.Regen -- Saves the integer value stored in the Hangar's Regen variable
function checkRegen()
if regen.Value == 1 then -- Hmmm...
model = backup:Clone() -- copies the copy of the plane
model.Parent = system -- adds the plane to the hangar
model:MakeJoints() -- ensures the bricks of the plane stick together (right?)
end
end
regen.Changed:connect(checkRegen) -- When a plane is created, the regen value changes
-- from nil to a value - triggering this call.
Tips
- Do not make your plane too big - or it will just wiggle on the hangar and will not fly. This is because it gets too heavy for the Engine to carry. Either make the plane smaller or add additional Engine parts.
- If you want your plane to look nicer, try making all visible surfaces Smooth.
- Do not place the tip at the bottom or near the bottom of the plane - or it will blow up whenever it lands. The tip is designed as a fail-safe to keep you from getting stuck to a wall during a crash.
Airplane platforms and Hangars
Here are some samples of more advanced hangars:
Additional Options
Bullet Distance
missile.CFrame = spn.CFrame * CFrame.new(0, 0, -35)
In the PlaneFlyer script, you can change the -35 to another number. This will make the bullet appear a different distance from the plane when you fire. You can also change the 0s to offset the bullet from the gun it comes out of. Do not change the -35 to a number too close to (or above) 0, or the plane will run into the bullets and die.
Renaming the Plane Model
function findPlane(player)
local list = player.Character:GetChildren()
for x = 1, #list do
if (list[x].Name == "Plane") then
local weld = list[x]:FindFirstChild("Parts"):FindFirstChild("Seat"):FindFirstChild("SeatWeld")
if (weld ~= nil) and (weld.Part1 == player.Character:FindFirstChild("Torso")) then
return list[x]
end
end
end
return nil
end
This part of the PlaneFlyer script will find the plane you are controlling when you do something in the plane. If you renamed your plane model, change the word "Plane" on the following line to what you named your model. This is in the PlaneFlyer script.
if (list[x].Name == "Plane") then
Multiple Guns
If your plane has more than 2 guns, change the PlaneFlyer script as follows:
Copy the fire function so that you have as many as you have guns on your plane. For example, my plane has -six- guns, so I will do this:
if (key=="f") and (bin.Reload.Value == 0) then fire(vehicle,plane.Gun1) fire(vehicle,plane.Gun2) fire(vehicle,plane.Gun3) fire(vehicle,plane.Gun4) fire(vehicle,plane.Gun5) fire(vehicle,plane.Gun6) bin.Reload.Value = 1 wait(1) bin.Reload.Value = 0 end
Note the six lines in the script corresponding to the six guns.
You can also change the wait(1) to another number if you want to be able to fire more rapidly, or more slowly (a wait of 0.5 means you can fire every half second, a wait of 2 means every 2 seconds)
And now for the stunt script sections. On both, the last line (before the end) is stuntdebounce = false. Before that line is a wait line. You can change this number if you want the plane to be able to do tricks more or less frequently. If you don't want your plane to have stunts, delete these lines. You can make the stunts operate more quickly or more slowly by changing the other waits (good if you have a big plane that turns slowly, and at the default speed will not complete the stunt properly).
Speed of the plane
In the FlyScript, you can change the line local spd = 3. You can change 3 to another number to make the plane fly faster or more slowly. A speed of 1.5 is half as fast as 3. If you don't know what to put, you can leave it at 3.
Reference page for Airplane Scripts
The following links will show you the specific scripts for the different features of an airplane.
This script goes in the plane itself, and makes your plane explode when it hits something. If you want you can change the blast radius.
This script goes in the plane's Parts and makes your plane regenerate when it leaves the hangar and is going at a certain speed.
Do not delete this script. It also makes it so you can control the plane when you sit down.
This script goes in the engine. This makes the plane regenerate when its Engine touches an object named Safe. This is usually a glass wall that does not collide and is placed in front of the plane hangars and deletes rockets that touch it.
If you are using the Safe objects to prevent hangar killings, use this script. Otherwise you should delete this. If you do not want autoregenerate, delete this script. (Useful if you have a really powerful plane that you want available only once every so often).
Go to the script in the platforms that your plane will be on:
system = script.Parent model = system.Plane backup = model:Clone() regen = system.Regen function checkRegen() if regen.Value == 1 then model = backup:Clone() model.Parent = system model:MakeJoints() end end regen.Changed:connect(checkRegen)
Delete this script if you are using the Safe blocks to prevent hangar killings, or if you do not want auto regenerate. Otherwise use it. Do the same for the script in the other station (it is exactly the same).
In the line model = system.Plane. change "Plane" to the name of your plane.
Optional Features
See Main Article: How to Make a Plane/Optional Features
Now that the basics of your plane are over, if you're one of those people that want your plane to bomb, cloak itself, and do other awesome things see the Optional Features Page.
You can add the following features:
- Bombing
- Shot Formations
- Cloaking
- Boosting
- Exhaust
- Landing Gear
- Rockets with Exhaust
- Balefire Attack
- Adding Homing Missiles
- Adding Bullets
- Adjusting Speed
- Adding Sequential Fire
- Making a Plane that gives tools
- Making your Plane change your team
Troubleshooting/FAQ
When I step onto the seat, he sticks on it but stays standing up for some reason. How do I fix this?
- A part of your plane is anchored, or joined to something it shouldn't be. Check that no parts of your plane are anchored, and that no parts are joined to anything not part of the plane (i.e., the ground, the plane platform, etc.)
My plane won't work!
- Follow the instructions carefully.
- Check spelling and case-sensitivity.
- Make sure no bricks are anchored on your plane.
- Check the scripts and the tool.
- Check the plane, its parts and scripts against a working model.
- Verify the RocketScript and FlyScript are disabled.
- Make sure the Engine brick is big enough, or the plane small enough.
- Verify that the seat size is (2,0.4,2) - a larger seat has caused some planes not to fly.

