So lately I’ve been trying to work with OOP with metatables. The game I’m creating could potentially have many entities being controlled at once. However I’ve come across something that I can’t wrap my head around.
I have my regular module that makes new objects for me. In this case, it’s a new enemy NPC.
local Enemies = {}
Enemies.__index = Enemies
function Enemies.new(name, node, pos, team)
print('Called')
local NewEnemy = {}
local EnemyData = EnemyDataService[name]
local NewZombie = EnemyModelService.GetNewModel(name)
if NewZombie then else print('Zombie', NewZombie, 'not found.') end
local RootPart = NewZombie['HumanoidRootPart']
local RotationControl = RootPart['RotationControl']
local PositionControl = RootPart['PositionControl']
local LeftLeg = NewZombie['Left Leg']
local AnimationController = NewZombie['AnimationController']
local Height = LeftLeg.Size.Y + (RootPart.Size.Y / 2)
--Stat Assigining
NewEnemy.Name = name
NewEnemy.Node = node
NewEnemy.Team = team
NewEnemy.Enabled = true
if EnemyData then
NewEnemy.HP = EnemyData.HP
NewEnemy.MaxHP = EnemyData.MaxHP
NewEnemy.Speed = EnemyData.Speed
end
NewEnemy.Root = RootPart
NewEnemy.Controller = AnimationController
NewEnemy.PosControl = PositionControl
NewEnemy.RotControl = RotationControl
PositionControl.MaxVelocity = EnemyData.Speed
RootPart.Parent:SetPrimaryPartCFrame(pos + (RootPart.CFrame.upVector * Height))
NewZombie.Parent = workspace[team]['Enemies']
return setmetatable(NewEnemy, Enemies)
end
return Enemies
For whatever reason, whenever I call Enemies.new() from another script with the arguments, it always runs twice.
I even went out of my way to make sure it only runs once. (There is only one line that uses Enemies.new() in all my scripts, it is not used anywhere else.) I ran it once from this location and got the following output.
Obviously, I only want one result from this function, but for some reason it’s giving me a duplicate, and that messes with my system when I am tracking the entities that are created.
Again, I’m fairly new to using this OOP, so I’m not entirely sure if this is normal behavior or I’m missing something. Any solutions or ideas for this would be appreciated.
Hmm, Personally I would just use @Kironte OOP Module which handles all the OOP properties like inheritances for you and the meta tables (It worked for me).
Also I don’t think it’s a good idea to be put zombies into the general Enemies object if you want to have multiple enemy types like zombies, wraiths, or robots to which you should use inheritance instead to which the zombies should inherit the enemies object which is how OOP should flow I believe.
Yeah I agree you should return the table instead of returning a setmetatable like the OOP tutorial format, I think the issue is it might be returning the metatable and also the table inside that table so it runs twice.
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
The short summary is that multiple modules were being used more than one time by another module (and the module containing the Enemies.new() was in one of the modules affected). After a chain link trackdown I found that the module running the .new() function was being called twice by a different module that was linked to multiple others. It was just something that you had to really look for to find. I just set up my system poorly, that’s all.
It doesn’t matter setmetatable returns the table your setting the metatable to . So when you do setmetatable(NewEnemy, Enemies) it actually does return the NewEnemy table.