Issue with results from OOP module

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.

image

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.

1 Like

Try putting a return NewEnemy; inside the Enemies.new function

3 Likes

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).

https://devforum.roblox.com/t/advanced-oop-implementation/741988?u=dthecoolest

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.

2 Likes

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

2 Likes

Thank you everyone for the input. I have found the reason to why this is happening, but due to it being rather complicated, I won’t explain it here.

3 Likes

Hmm, I’m pretty interested. Any short summary on the problem and how you fixed it?

2 Likes

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.

4 Likes

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.

4 Likes