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.