I’m working on a character model, I have put together a base class, but when I create a sub-class, I am unable to call the methods from the subclass
BASE CLASS:
--[[
- CHARACTER ATRIBUTES:
- Character
- Species
- Level
- EXP
- Stamina
- MaxStamina
- Oxygen
- Max Oxygen
]]
local Character = {}
Character.__index = Character
function Character.new(species)
local self = setmetatable({}, Character)
self.Charcater = nil
self.Species = species
self.Level = 5
self.Exp = 0
self.MaxExp = 25
self.MaxExpRate = 25
self.Stamina = 100
self.MaxStamina = 100
self.Oxygen = 100
self.MaxOxygen = 100
return self
end
function Character:Connect(model)
self.Character = model
self._OnDied = self.Character.Humanoid.Died:Connect(function()
self:Died()
end)
end
function Character:Died()
self:Destroy()
end
function Character:IncreaseExp()
self.Exp += 5
while self.Exp >= self.MaxExp do
self:LevelUp()
self.MaxExp = math.floor(self.MaxExp * 1.5)
end
end
function Character:LevelUp()
self.Level += 5
end
return Character
SUB-CLASS:
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local CHARACTER_CLASS = require(ReplicatedStorage.MODULES.CLASSES.CHARACTER)
local MermaidClass = {}
MermaidClass.__index = MermaidClass
setmetatable(MermaidClass, CHARACTER_CLASS)
function MermaidClass.new()
local self = setmetatable(CHARACTER_CLASS.new(), MermaidClass)
return self
end
function Mermaid:IncreaseOxygen()
---stuff
end
return MermaidClass
Real solution: don’t use inheritance and OOP inside a language that does not support/optimize either.
You should think instead of using an ECS-like system.
local Players = game:GetService("Players")
local levels:{[Player]:number} = {}
Players.PlayerAdded:Connect(function(plr):()
--datastore thing probably
local dataStoreValue = nil
levels[plr] = dataStoreValue or 1
end)
Players.PlayerRemoving:Connect(function(plr):()
--cleaning up and saving to datastores idk
levels[plr] = nil
end)
I’m not looking to set this up as a data store type system, it’s to build my characters and provide functions for them to be able to customize them, using OOP.
Luau does not support true OOP. The closest you can get is closures or tables with/without metatables, but they’re fragile, verbose, and scale horribly - you’ll go insane before you get anything complex working reliably, and even then it all will be a waste because of the runtime overhead they have and the compiler never attempting to unwrap them into something sane.
An Entity-Component-System pattern fits Luau far better. It’s basically functional programming with state, which aligns perfectly with the language’s design. You get modularity, customization, and performance without fighting metatables or inheritance chains.
I appreciate the advice, but I posted this in hope’s to receive a solution to my problem, not a paragraph on why you don’t like Roblox’s OOP system, I have been experimenting with this format from a tutorial I saw for some time now trying to learn different ways to use it so I don’t think they would’ve posted it if it was defective, I don’t mean for this to come off as rude but I am not looking for a lecture here, I’m looking for a direct resolve to my issue.
Correct me if I’m wrong, but I believe self will be nil in your .new() functions. self only exists in methods using the semicolon operator (:). self is actually syntax sugar for just passing it in the first argument of the function.
I think the right option is to do this:
function Character.new(species)
local character = setmetatable({}, Character)
character.Charcater = nil
character.Species = species
character.Level = 5
character.Exp = 0
character.MaxExp = 25
character.MaxExpRate = 25
character.Stamina = 100
character.MaxStamina = 100
character.Oxygen = 100
character.MaxOxygen = 100
return character
end
There is no such thing as a “Roblox OOP”, By “Roblox OOP,” you may refer to instance API Roblox lets you call through Luau.
The thing you might want to refer to is called Prototype OOP, or, as I like to call it, “cope OOP”.
If you are going to write proto OOP, then at least write it properly.
--[[
- CHARACTER ATRIBUTES:
- Character
- Species
- Level
- EXP
- Stamina
- MaxStamina
- Oxygen
- Max Oxygen
]]
local Character = {}
Character.__index = Character
function Character:Connect(model)
self.Character = model
self._OnDied = self.Character.Humanoid.Died:Connect(function()
self:Died()
end)
end
function Character:Died()
self:Destroy()
end
function Character:IncreaseExp()
self.Exp += 5
while self.Exp >= self.MaxExp do
self:LevelUp()
self.MaxExp = math.floor(self.MaxExp * 1.5)
end
end
function Character:LevelUp()
self.Level += 5
end
return {Character=Character,new=function():()
return setmetatable({
self.Charcater = nil,
self.Species = species,
self.Level = 5,
self.Exp = 0,
self.MaxExp = 25,
self.MaxExpRate = 25,
self.Stamina = 100,
self.MaxStamina = 100,
self.Oxygen = 100,
self.MaxOxygen = 100}, Character)
end}
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local CHARACTER_CLASS = require(ReplicatedStorage.MODULES.CLASSES.CHARACTER)
local MermaidClass = {}
MermaidClass.__index = MermaidClass
setmetatable(MermaidClass, CHARACTER_CLASS.Character)
function MermaidClass:IncreaseOxygen()
---stuff
end
return function():()
local self = setmetatable(CHARACTER_CLASS.new(), MermaidClass)
return self
end
You create method for non existing variable in MermaidClass
Is the ECS system implemented using Dictionaries?
I havent fully done OOP on roblox, but it feels a bit difficult to do, languages like
Java has a really nice OOP, but lua feels more difficult to do OOP.
Yea I did see that, Idk how I missed it, I also noticed the functions do work but for some reason they just don’t pop up in the list when typing it out
Because you can’t do OOP in Luau at all, there are no opcodes for true OOP, nor are there any compiler instructions.
That also depends; ECS is usually implemented either via an array with a unique number or via a dictionary.
Realistically, it’s always dictionaries and maybe buffers and even rarer arrays.