You are storing the new(index) into the slot module, not the slot object that gets created.
do
newSlot.Index = index
You are storing the new(index) into the slot module, not the slot object that gets created.
do
newSlot.Index = index
How would I have classes inherit metamethods such as __tostring
or __add
?
Since the metamethod invocation uses rawget
, it doesnt seem to look up the chain of classes to find the base implementation.
i dont know too much about OOP and I am trying to learn. My question is: how would a car table became a real car on roblox? I would have to call Car.new() and latter create the car with the info on table? That does not make sense. Can I make the Car.new() return an actual car object?
In the constructor (Car.new) you would create the car model and then usually youâd have a property like car.Model or car.Instance that you assign the Model to.
Now when you want to interact with the model you just access the property.
In other cases where you donât need the extra functionality you can return the model directly instead.
This comes with the disadvantage that now you canât use methods like car:Accelerate()*
This would be a easier way,
local Car = {}
Car.__index = Car
function Car.new(position, driver, model)
local self = setmetatable({
Position = position,
Driver = driver,
Model = model,
}, Car)
return self
end
return Car
It may be easier for you, but your code looks a bit more messy than the OPâs code.
Messier? It looks more readable than just doing plain old newcar.VAR = var,
For you it does, for others it there is a chance itâs not.
Personally I prefer this version:
function Car.new(position, driver, model)
local self = setmetatable({}, Car)
self.Position = position
self.Driver = driver
self.Model = model
return self
end
This is the least ambiguous version IMO albeit admittedly it does look redudant compared to yours.
Alternate way of formatting
----------------------------------------------------
-- Define Class Attributes
----------------------------------------------------
Car = {
Position = nil;
Driver = nil;
Model = nil;
Speed = nil
}
----------------------------------------------------
-- Define Class Methods
----------------------------------------------------
function Car:Boost()
self.Speed = self.Speed + 5
end
----------------------------------------------------
-- Define Class Constructor
----------------------------------------------------
function Car.new(tbl)
local newcar = tbl or {}
setmetatable(newcar, Car)
Car.__index = Car
return newcar
end
If I have this:
local PlayerModule = {}
PlayerModule.__index = PlayerModule
-- Constructer function to create a new character
function PlayerModule.new(character)
local newCharacter = {}
setmetatable(newCharacter, PlayerModule)
newCharacter.Name = character.Name
newCharacter.Stamina = 100
newCharacter.BonusHealth = 0
table.insert(characters, newCharacter)
return newCharacter
end
return PlayerModule
How would I get the newCharacter that I created without doing .new() every time. I thought of making a table and inserting the newCharacter into that table to get it that way. Am I missing something about OOP here?
So my solution is now this:
local PlayerModule = {}
PlayerModule.__index = PlayerModule
local characters = {}
-- Constructer function to create a new character
function PlayerModule.new(character)
local newCharacter = {}
setmetatable(newCharacter, PlayerModule)
newCharacter.Name = character.Name
newCharacter.Stamina = 100
newCharacter.BonusHealth = 0
table.insert(characters, newCharacter)
return newCharacter
end
-- get the character
function PlayerModule:GetCharacter(name)
for i, v in pairs(characters) do
if v.Name == name then
return v
end
end
end
return PlayerModule
Iâm not sure if this is the correct way to do it.
The character you make is returned from the function call.
local playerModule = require("PlayerModule")
local myChar = playerModule.new(character)
After that, you use myChar to refer to the made character from then on, using .new again will make a separate character; resulting in the resetting of values.
Your solution would allow you to create a player in one script and then find a reference to it from a separate script. This is quite useful if you have things broken apart into multiple scripts;
As far as keeping track of a data structure after you make it, poking it into a table or variable is pretty much your only option. The question is where, if the creation is triggered in the same script as all other uses, you can just keep it with the rest of your code.
Your solution has it in the module to be reference along with creation which works well with keeping everything player related together.
Alternatively, you could create a singleton module script to hold object references.
self
is equal to Car
. We can rewrite that code as follows:
function Car.Boost()
Car.Speed = Car.Speed + 5
end
self
is just syntax sugar. But remember that you have to use a colon if you want to use self
. Otherwise - if you use a dot and not a colon - self
will be equal to nil
.
Because the question was discussed elsewhere follow below for any people from the future.
Are there any good practice methods to make a :CleanUp() method on an object, and have it work with both this class and inherited classes?
Wow! 9 years old and still excellent.
Is there some way I can get type hinting from Roblox-LSP using the example?
--module script called Car in game.ReplicatedStorage
Car = {}
Car.__index = Car
function Car.new(position, driver, model)
local newcar = {}
setmetatable(newcar, Car)
newcar.Position = position
newcar.Driver = driver
newcar.Model = model
return newcar
end
function Car:Boost()
self.Speed = self.Speed + 5
end
return Car
--main script
Car = require(game.ReplicatedStorage.Car)
carLot: {Car} = {}
-- as before
The last line, carLot {Car} = {}
, gives my Roblox-LSP extension cause to complain:
Undefined type
Car
.Roblox LSP Diagnostics.(undefined-type)
Thanks
You have to make sure you define the type.
type carlot = {typeof(Car.new())} -- Note: A car object is not constructed during type definition
-- It's easier than manually doing:
-- ^usually
-- type carlot = {
-- [number]:{
-- Position:Vector3,
-- Driver:Player?,
-- Model:Model,
-- };
-- }
-- Note: 'typeof' really only properly evaluates value types if you define the types somewhere along the line (ie: parameters and or return value(s), etc..)
local Carlot:carlot = {}
Youâre a life-saver, thanks. Using this extensively on much better code now.
Youâre welcome.
Declaring types is very important for aiding readability and maintainability in a similar way commenting parts of your code does.
iâve always considered myself intermediate but after going down this rabbithole i realized how much of a beginner i am,but i managed to grasp how these custom âclassesâ can be used:
lets say we want to create candy,instead of having to go through every detail everytime we want to create a new one,we could create a candy class,meaning by just using 'CandyMaker.new(flavor,size) we could create a piece of candy
,now lets say we want to create a lollipop for example,now lollipop is basically candy except it has more properties,it has a taste,and size,but it also has special properties such as the length of the lollipop stick for example,so we could add those functions into the âLollipopMakerâ module, that, by my opinion, saves A LOT of time