Roblox OOP (Object Oriented Programming)

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.

image

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 :

image

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.

image

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()

image

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 :
image

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,
image

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) :brain:

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 :
image

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!
image

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.


I hope you found this helpful and if you have any feedback or questions you can leave them down below!! :+1:


111 Likes

I’m still learning OOP and it’s kind of fun to make this! Great tutorial! :grinning_face_with_smiling_eyes:

6 Likes

Thank you !! Please do not hesitate to ask me if you have any questions!!

5 Likes

I’m gonna have to bump this, it’s amazing!

5 Likes

I was having a hard time understanding what the whole ._index did but after reading this post I understand now! Thanks! This helped me understand OOP a bit more!

9 Likes

Hi! Thank you very much for this tutorial, I was able to understand metatables better! Is there any way to implement function overwriting? Thanks :grinning:

2 Likes

Hi,I know it’s been several month since you did this post but can you answer a question that has been bothering me for a while and it’s that why do people use self and why most oop are using it .

Thanks either way :grinning:

2 Likes

Sorry for the late reply, if you haven’t already figured it out by now, self is basically a way to call the table of information you’ve created in your example.New() function.

If you want a more detailed explanation with examples, let me know!

1 Like

I apologize for the late reply (I really outdid myself with that one)

I’d like you to elaborate on what you mean by function overwriting. Like the ability to reconstruct a function and it’s ability from scratch? I’m not too sure what you mean.

2 Likes

If you dont mind answering another question and that is why is oop so important I mean like a table that just contain info about the gun how do people find that useful I just dont get why people use it

1 Like

There is already a tutorial from 2014 about this…


though I appreciate this, I am using OOP now :wink:

3 Likes

You can have not only info but everything you need for your gun.

People will use this because it is a more efficient approach, that’s really it. You don’t have to use OOP at all but it makes it much easier for you as your games get more complicated. Duplicating a gun would not require making a new script, using classes you can make new guns with little effort etc

2 Likes

I cant seem to see any images. Is it my device problem or is it gone?

4 Likes

I can’t seem to see any either, I’m not sure why the images stopped appearing, I’ll try to re-upload the images, Thank you for your patience!

5 Likes

wait how would you use the “powerup” in this case

1 Like

Why people still use OOP while we got module… 4 year I hear that, 4 year I never understand how the hell it can help…

1 Like

It simplifies things and makes them easier to maintain and modify. You can go to one script where that one thing is located, rather than searching through multiple scripts to find it.

1 Like

That what I call a module… It do that exactly

1 Like

I just realized this topic is about OOP and not modules

1 Like
1 Like