What is Object Oriented Programming (OOP) ?
Hello there! Welcome to the OOP tutorial I created with the knowledge I’ve gained over the last few months.
Object-oriented programming (OOP) is a programming approach in which classes of
objects are identified and closely related to the methods (functions) with which they are
associated. It also incorporates concepts like as attribute and method inheritance.
Simply put, OOP will assist you in creating more efficient scripts in the long run.
However, you may be wondering why and how right now. And that is just what I intend to teach you.
So lets just say you want to make a gun system for your game.
Disclaimer (I’m not going to show you how to create the gun in detail, but rather the approach OOP will provide Instead of using standard scripting)
So the first thing I would do is obviously have my set up for my OOP scripting.
As you can see what I usally do is have a folder in ReplicatedStorage
That is called shared which will have modulescripts that want to be accessed in the client and/or the server. After that I have 1 script in StarterGui/StarterCharacterScripts
(your preference) That will be the script for the client (local script).
After that I would just have a script Situated in ServerScriptService
and my server sided modules in ServerStorage
.
After that, we can begin working on the module script, which will serve as the foundation for all of our guns. Basically, we’ll have one module for all of the guns, and if there are any special weapons, such as a rocket launcher, we’ll base it on that class and add to it.
local Gun = {}
return Gun
So now that we have our module set up and configured, Making a function to produce a new gun is always the first thing I do. Modules allow you to create functions that are related to the module, like this one :
local Gun = {}
function Gun.New()
end
return Gun
Now that we have created our function, we need this to be working properly and actually creating something, So lets add that right now.
local Gun = {}
function Gun.New(Damage, Auto, Ammo)
local newGun = {}
newGun.Damage = Damage
newGun.Auto = Auto
newGun.Ammo = Ammo
end
return Gun
So as you can see now we make a table called newGun
Inside the function which is going to have all the information we need for the gun, the information will be passed on from the script which we will use to create the gun, But in this moment if we even try to access it, it will create a new table but we won’t be able to use any functions on it. So lets make a function.
local Gun = {}
function Gun.New(Damage, Auto, Ammo)
local newGun = {}
newGun.Damage = Damage
newGun.Auto = Auto
newGun.Ammo = Ammo
end
function Gun:Shoot()
if self.Auto == false then
self.Ammo -= 1
elseif self.Auto == true then
self.Ammo -= 5
end
end
return Gun
So now that we have a function that will remove ammo when you shoot we need to try to access it, this is where you realize that you cannot access the function because the script won’t even find the function.
-- Script in ServerScriptService
local Gun = require( game:GetService("ServerStorage").Modules.Gun)
local Glock = Gun.New(10, false, 100)
Glock:Shoot()
If we try to do that we will get this error :
And that is because it cannot find the function :Shoot that we are trying to call, Maybe because the function Shoot is not is not allied to the new gun we are making…? Yes Indeed this is why this is happeneing, The self
we are referencing Here
function Gun:Shoot()
if self.Auto == false then
self.Ammo -= 1
elseif self.Auto == true then
self.Ammo -= 5
end
end
Is actually equal to the whole module if we print it.
But we dont want it to be equal to the module, we want it to be equal to the new gun we are creating with our Gun.New()
function. This is why metatables and metamethods are useful.
The first thing we are going to do to make this work is that we are going to set the index
of the whole module to itself using .__index
to make sure there will be no confusion, but the real use of this is when we are going to try to use our new gun we will be redirected to the module since the new gun doesn’t have a :Shoot()
function and this will allow us to use it.
local Gun = {}
Gun.__index = Gun -- here we set the index of the module to itself using .__index.
function Gun.New(Damage, Auto, Ammo)
local newGun = {}
newGun.Damage = Damage
newGun.Auto = Auto
newGun.Ammo = Ammo
end
function Gun:Shoot()
print(self)
if self.Auto == false then
self.Ammo -= 1
elseif self.Auto == true then
self.Ammo -= 5
end
end
return Gun
Now that we’ve done that, we can move on to connecting the new gun to the gun module’s functions. Metatables can be used to do this.
local Gun = {}
Gun.__index = Gun
function Gun.New(Damage, Auto, Ammo)
local newGun = {}
newGun.Damage = Damage
newGun.Auto = Auto
newGun.Ammo = Ammo
setmetatable(newGun, Gun)
end
function Gun:Shoot()
print(self)
if self.Auto == false then
self.Ammo -= 1
elseif self.Auto == true then
self.Ammo -= 5
end
end
return Gun
Now if we play you will see that Ta Da!! Nothing is working and we still have the same error. Why?? Maybe because we forgot to return the new gun so that it knows that it’s calling the new gun object.
local Gun = {}
Gun.__index = Gun
function Gun.New(Damage, Auto, Ammo)
local newGun = {}
newGun.Damage = Damage
newGun.Auto = Auto
newGun.Ammo = Ammo
setmetatable(newGun, Gun)
return newGun -- here you are returning the object to the function.
end
function Gun:Shoot()
print(self)
if self.Auto == false then
self.Ammo -= 1
elseif self.Auto == true then
self.Ammo -= 5
end
end
return Gun
Now this is what happens if we call it in our script and construct a new gun, then try to shoot it :
--Server Script in ServerScriptService
local Gun = require( game:GetService("ServerStorage").Modules.Gun)
local Glock = Gun.New(10, false, 100)
Glock:Shoot()
It will print the guns components which means it is working!!!
Now lets just make several guns and set some different values and see how everything is working.
--Server Script in ServerScriptService
local Gun = require( game:GetService("ServerStorage").Modules.Gun)
local Glock = Gun.New(10, false, 100)
local Ak47 = Gun.New(20, true, 100)
Glock:Shoot()
Ak47:Shoot()
Now that we made another gun with different properties this is what we get when we run the game :
The first gun is a Glock so it only looses 1 bullet when it shoots, the other gun is an ak47 that is fully auto which means it will shoot 5 times per trigger. Now lets Name the guns just so we can see the table better.
local Gun = {}
Gun.__index = Gun
function Gun.New(Damage, Auto, Ammo, Name)
local newGun = {}
newGun.Name = Name
newGun.Damage = Damage
newGun.Auto = Auto
newGun.Ammo = Ammo
setmetatable(newGun, Gun)
return newGun
end
function Gun:Shoot()
print(self)
if self.Auto == false then
self.Ammo -= 1
elseif self.Auto == true then
self.Ammo -= 5
end
print(self.Ammo)
end
return Gun
Here I added a name property so now we can pass the name of the gun we are creating.
Now this is our server script :
local Gun = require( game:GetService("ServerStorage").Modules.Gun)
local Glock = Gun.New(10, false, 100, "Glock")
local Ak47 = Gun.New(20, true, 100, "Ak-47")
Glock:Shoot()
Ak47:Shoot()
We are passing the name and Ta Da!! This is what we get,
We get individual and sorted tables that have our data of our guns. Now we have 2 guns that work with 1 script which is the whole point of OOP. I could make as much guns as I want, But what if I wanted to make a rocket launcher?? It will be a bit different from a standard gun right…? This is where inheritance comes in, we can make other types of guns that will inherit from the basic functions of a gun.
Learning about OOP Part 2 (Inheritance)
So lets start by making a brand new module for our rocket weapons, It will be able to get used for things such as rocket launchers, grenade launchers, tanks etc…
So lets make a separate module that we will call rocket :
Now that we have the module we will want to use it just like the gun module, So lets set up the base of the module :
--Rocket Module
local Rocket = {}
Rocket.__index = Rocket
function Rocket.new(Damage, Auto, Ammo, Name, SpecialMove)
local newRocket = {}
newRocket.Damage = Damage
newRocket.Auto = Auto
newRocket.Ammo = Ammo
newRocket.name = Name
newRocket.SpecialMove = SpecialMove
setmetatable(newRocket, Rocket)
return newRocket
end
return Rocket
But of course now nothing will happen and we won’t be able to use our :Shoot
function on the rocket we are making, So the first thing we will do is require our Gun Module so that we can basically make the Rocket inherit from it.
local Gun = require(game:GetService("ServerStorage").Modules.Gun)
local Rocket = {}
Rocket.__index = Rocket
function Rocket.new(Damage, Auto, Ammo, Name, SpecialMove)
local newRocket = {}
newRocket.Damage = Damage
newRocket.Auto = Auto
newRocket.Ammo = Ammo
newRocket.name = Name
newRocket.SpecialMove = SpecialMove
setmetatable(newRocket, Rocket)
return newRocket
end
return Rocket
So now that we have required our gun module you may wonder how are we going to make the Rocket inherit from the gun and be able to use our :Shoot
function that we have in the gun module. All we need to do for that is the same thing we did to make the new gun table able to use it but with the Whole Rocket module, Just like this :
local Gun = require(game:GetService("ServerStorage").Modules.Gun)
local Rocket = {}
Rocket.__index = Rocket
setmetatable(Rocket, Gun)
function Rocket.new(Damage, Auto, Ammo, Name, SpecialMove)
local newRocket = {}
newRocket.Damage = Damage
newRocket.Auto = Auto
newRocket.Ammo = Ammo
newRocket.name = Name
newRocket.SpecialMove = SpecialMove
setmetatable(newRocket, Rocket)
return newRocket
end
return Rocket
Now we are setting the table Rocket to Gun which means we can take from the Gun module and now we should be able to call our functions from the gun module like :Shoot
, So lets do exactly that and test it out :
--server script
local Gun = require( game:GetService("ServerStorage").Modules.Gun)
local Rocket = require(game:GetService("ServerStorage").Modules.Rocket)
local Rocket = Rocket.new(50, false, 10, "Rocket", "BOOM BOOM SPECIAL MOVE")
local Glock = Gun.New(10, false, 100, "Glock")
local Ak47 = Gun.New(20, true, 100, "Ak-47")
Glock:Shoot()
Ak47:Shoot()
Rocket:Shoot()
And Tada!
The Shoot function works for the rocket and it still has the special attack that we made for it. This is basically how you should use OOP (object oriented programming)
for your games.