Object Oriented Programming (OOP) is a paradigm used to keep large projects organized, which is done using
objects. Whether you realized it or not, you've more than likely used objects in the past! Pretty much
everything in Roblox is an object, or better known to you as an "instance". Instances are just another word for objects in rbx.lua.
Let's look at a real world example, dogs for example. What do dogs do a lot? Bark. What are some attributes
to a dog? Their fur color, what breed they are, what size they are. What else is there about dogs? No dog
is like another dog!
Just from the example of a dog, you've learned three important parts about what makes up an object in coding.
-Identity
That an object is unique from other objects.
-Behavior
What an object can do.
-State
What an object looks like and/or what features it has.
In rbx.lua we use ModuleScripts to store stuff like classes, so make sure you use them when creating classes.
When creating an object in another language you would usually create a class- a class is just a template
for creating an object -but in lua we do not have classes.
You may wonder how we would get around this to implement OOP into lua. Well that's easy! In lua
we have a feature called "metatables" and "metamethods" which allows coders of lua to implement new features
easily to the language. After all, lua is a language that's meant to be added onto.
A metatable is a table of functions that controls how a different table acts. And metamethods are functions
that are stored inside a metatable. To see a list of metamethods please see the metatables article on the
Roblox Wiki.
Now let's get down to setting up our class with metatables and metamethods.
local dog = {}
dog.__index = {}
so we first create a table called dog, then we set the .**index of that table back to that table. We can
do this because that table is empty so there's no harm in setting the __index to the same table.
.**index is a metamethod that is called whenever we add a new key to the table, so it will add that
function or variable automatically to any object we create.
Let's continue.
local dog = {}
dog.__index = {}
function dog.create(name, color, size, breed)
local object = setmetatable({
name = name,
color = color,
size = size,
breed = breed
}, dog)
return object
end
return dog
What's been done now is that we made a "create" function to create a dog object. We also made a table that
contained the variables "name", "color", "size", and "breed". These variables' values are set according to the parameters in the function. The table's metatable is then set to the dog table that way it will be able to use any methods and variables we set to the dog table.
We return the object so we can have access to that object, it's properties, it's methods, and anything else
we add to it.
We also return the dog table so when we require the ModuleScript we can access everything inside from other
modules or scripts.
Now that we have the very basis of our class setup, let's add some functionality to it!
local dog = {}
dog.__index = dog
function dog.create(name, color, size, breed)
local object = setmetatable({
name = name,
color = color,
size = size,
breed = breed
}, dog)
return object
end
function dog:bark()
print(self.name .. ": woof!")
end
return dog
So now you've probably noticed a few different fews. Instead of using a . operator for the bark function, we used the : operator.
We do this so we can use the "self" variable that allows us to access other methods
and variables that belong to that specific object, we'd also call that method with the : operator
and any other methods that use it. However, variables are accessed with the . operator.
So in this example, we use the self operator to access the name of the dog.
Since we can't use ModuleScripts in this Tutorial, we'll pretend we created that ModuleScript and that it is
stored in ReplicatedStorage and the name of the ModuleScript is "dog".
local replicatedStorage = game:GetService("ReplicatedStorage")
local dogClass = require(replicatedStorage.dog)
local rex = dogClass.create("Rex", "yellow", "medium", "Golden Retriever")
rex:bark() --prints "Rex: woof!"
local lola = dogClass.create("Lola", "brown", "small", "Apple Head Chihuahua")
lola:bark() --prints "Lola: woof1"
What we did here was get the ReplicatedStorage service, then we required the dog ModuleScript as the dogClass
variable. Then we created a dog object from the dog class named Rex under the rex variable,
and called the bark method on Rex. And finally, we then created another dog object from the dog class named
Lola under the lola variable and then called the bark method on Lola.
As you can see when we call the bark method on those two different objects, it prints two different strings:
"Rex: woof!" and "Lola: woof!".
When requiring a ModuleScript do remember that it will take on the form of whatever type of script required it.
If a Script required it the ModuleScript would error if there was any LocalScript only code in there. And same
with LocalScripts, any code meant only for Scripts would error in a ModuleScript required by a LocalScript.
And if a ModuleScript was required by another ModuleScript and however far back it went on the require, it
would only be able to use the code meant for whichever type of Script required all those ModuleScripts.
-Create a cat class with name, color, breed, and size variables with a meow method -Make a base dog class that can be inherited by another class that is specific breed. (Don't worry if you can't
do this, inheritance is a bit hard to do for beginners of OOP, but you should be able to do this theoretically
even as a beginner.)
-Make a person class with a name, job, race, and hair color variables with speak, sleep, eat, and work methods