I was trying to do exactly what you suggested here:
I’ve created a custom :Destoy() method inside my class/metatable. From that method I destroyed a model associated to my class and then set the metatable to nil doing setmetatable(self, nil).
After I’ve executed this function I can still print the values of the current Instance (obviously as they’re stored in a variable) and I was wondering if there’s any way to also set that variable to “nil” or to get a reference of the metatable instead of a copy so I can achieve that.
Thank you!
I’d be happy to help but to avoid cluttering the comments of this post would you mind sending me a devforum message with your question and your code? I’m a bit confused on what you are asking specifically so we can clear that up in private messages.
I have created a class/prototype via a module script on the server. However, whenever I pass this onto the client via a remote event, it returns back to acting like a standard table, meaning I cannot run my functions as it returns ‘attempt to call a nil value’.
This is a great tutorial!
I wish Roblox included this tutorial on their wiki/docs for beginners.
Would be even better if Lua/Luau just had classes to make things easier but that’s just the design of the language I suppose.
I’ve been on Roblox for about 10 years and ever since I started programming; in almost every script that I’ve ever seen that wasn’t written by me, I’ve noticed the lack of object oriented programming.
I wonder why OOP isn’t a standard thing in Roblox considering it makes game development so much easier and more blueprint-based.
Just think about all those models that have copy-paste or duplicate scripts in them because the original writers couldn’t be bothered to use metatables and make it object-oriented, ouch.
I hope this tutorial helps people and makes them more aware about the usefulness of OOP.
I really wish it was used more often in Roblox Lua, or Lua in general.
Block = {}
Block.__index = Block
function Block.new(position)
local newblock = {}
setmetatable(newblock, Block)
newblock.part = Instance.new("Part")
newblock.part.Name="myPart"
newblock.part.Position = Vector3.new(-10,0,-10)
newblock.part.Parent = workspace
return newblock
end
function Block:ChangeColour()
self.Color = Color3.fromRGB(190, 183, 80)
end
return Block
--- main script
local ServerStorage = game:GetService("ServerStorage")
local Block = require(ServerStorage.Block)
local block1 = Block.new(Vector3.new(10,0,-10))
local b=workspace:FindFirstChild("myPart")
--this next line give an error : ChangeColour is not a valid member of Part "Workspace.myPart"
b:ChangeColour()
You defined the function ChangeColour inside the Block table, but you are trying to call it on an instance. The function is not defined for the instance hence the error. You should be doing block1:ChangeColour instead to resolve the error. Also, your ChangeColour function body should be:
function Block:ChangeColour()
self.part.Color = Color3.fromRGB(190, 183, 80)
end
I think the confusion you may be having is you might think once you call the new function, your part that gets created somehow inherits the data that you defined in the Block table, but that isn’t true. Your code is essentially wrapping the functionality of the new part you create, so all of your custom functions need to be called using the wrapper object, and not the actual instance that gets created upon calling the new function. In your code, the wrapper object would be block1 and the actual instance would be b. Hope that helps!
Then how do I reference the wrapper object and hence its methods once I have the part?
The change colour function is arbitrary I accept the code in there was wrong, but I’m just trying to figure out how to get the the object in the table from the part so I can call the methods on the part.
And yes I could use block1 but you may not always have that reference - you may just have the part from a collision event for example.
If you did not have a reference to your custom object but did to the instance then you would have to make a function that returns your custom object given the parameter of an instance. Example code:
local cache = {}
local proto = {}
proto.__index = proto
function proto:ChangeColour(colour)
self.part.Color = colour
end
return {
new = function(name, pos)
local part = Instance.new("Part")
part.Name = name
part.Position = pos
part.Parent = workspace
local self = {part = part}
cache[part] = self
return setmetatable(self, proto)
end,
-- you can have something like this 'get' function or allow for accessing 'cache' directly
get = function(instance)
return cache[instance]
end
}
local Block = require(...)
local block_1 = Block.new("Example", Vector3.new(0, 0, 0))
local obj_1 = workspace:FindFirstChild("Example")
print(assert(block_1 == Block.get(obj_1))) -- should output true
This is a great article that helped me understand metatables and object orientation. Thank you. Although I saw it a long time ago, I recommend this article to people around me.
Well written, many tutorials just tell you how to do it without actually explaining why you do it. This one actually elaborates on the purpose of each step
I had a Question about the oop child I care I have the basics and for a quest system I need to describe if the quest is a quest or it is necessary to find things, or if it is a quest or must kill enemies or other… and for its I must also assign how many must find/ kill, who must find/ kill I do not understand how to do it, sure with tables?