I’ve recently come back from a break I took from studio and I am now learning Object Oriented Programming. It’s a little confusing and I tried using it to make an enemy system and I’m kind of confused.
I have a main module called Enemy, a descendant module called Zombie, and a normal script called Main. I was wondering if someone could guide me on how to improve and organize the code.
Enemy main module:
local Enemy = {}
Enemy.__index = Enemy --Sets index to itself
function Enemy.new(hp, spd, dmg) --Function to create a new Enemy and variables
return setmetatable({
Health = hp,
Speed = hp,
Damage = dmg,},
Enemy)
end
return Enemy
Zombie module:
local Enemy = require(script.Parent.Enemy) --requires other module
local Zombie = {}
function Zombie.new(model) --Allows the creation of a zombie and model
return setmetatable({Enemy.new( --Sets variables of hp, speed, and dmg
100,
12,
20)},
Zombie)
end
return Zombie
Finally, the normal script
local Zombie = require(script.Parent.Zombie) --Is their a way to require all the modules so I can add more enemies like a skeleton for example?
local ZombModel = game.ReplicatedStorage.EnemyModels.ZombieModel
Zombie.new(ZombModel)
ZombModel.PrimaryPart.CFrame = CFrame.new(430, 4, -8) --Theirs probably a better way to do this like adding a new function or var to enemy. Please let me know how if possible
ZombModel.Parent = workspace
Well to improve the code you can definitely utilize the fact that it is Object Oriented more. One way you can do this is I see in your normal script you create a new zombie object with “Zombie.new(ZombModel)” but you dont actually set that as a variable which means you created the object but you cant ever use it in the future, So you could instead do "local Zombie = Zombie.new(ZombModel), this will allow you to edit properties of the zombie object in the future, for instance you have a line of code that changes the “ZombModel”'s primaryParts CFrame, instead of this you could reference the zombie object variable I talked about (local Zombie = Zombie.new(ZombModel)) and do Zombie.Model.PrimaryPart.CFrame = blabla. to do this you would have to do add a value called Model to the Zombie.new() function in the Zombie module by doing
return setmetatable({Enemy.new(
100,
12,
20)
Model = model}, – added value to the object
Zombie)
Now this made it so you are actually accessing the zombie object and using the OOP to your advantage, otherwise you have created the object for nothing.
Sorry if this was confusing I would assume it is because I can be bad at explaining things, feel free to ask any questions.
function Zombie.new(model)
return setmetatable({Enemy:new(
100,
12,
20,
model --This is what I added
)},
Zombie)
end
return Zombie
But I don’t know how to access the model from the regular script.
I tried this and it didn’t work
local ZombieModule = require(script.Parent.Zombie)
local ZombModel = game.ReplicatedStorage.EnemyModels.ZombieModel
local Zombie = ZombieModule.new(ZombModel)
Zombie.Model.PrimaryPart.CFrame(0,0,0)
function Enemy:new(hp, spd, dmg, mod) -- and this
return setmetatable({
Health = hp,
Speed = hp,
Damage = dmg,
model = mod --I added this
,},
self)
end
still doesn’t work and I think the issue is the regular script because it doesnt know what Zombie.Model is because it isn’t defined but I don’t know how to access the model variable from the module script and use it in the regular script.
local enemyClass = {}
enemyClass.__index = enemyClass
function enemyClass.new(hp, spd, dmg, model)
local this = setmetatable({}, enemyClass)
this.Health = hp
this.Speed = spd
this.Damage = dmg
this.Model = model
return this
end
--//Some other script
local myEnemy = enemyClass.new(10, 10, 10, workspace.someModel)
Then call the .new method to create new enemy objects passing in whichever arguments you want
I do see you are trying to do this in an unusual way, I also notice that the enemyModule does virtually nothing and you are returning the return value of the setmetatable function, I am pretty sure this will return void(nothing) so instead do this in the zombie module:
function Zombie.new(model, hp, spd, dmg)
local newZomb = {}
setmetatable(newZomb, Zombie)
newZomb.Model = model
newZomb.Health = hp
newZomb.Speed = spd
newZomb.Damage = dmg
return newZomb
end
return Zombie
and when doing Zombie.new() in the main script do Zombie.new(ZombModel, hp, speed, damage) – replace hp speed and damage with their proper values
Okay thanks for the advice. I removed the zombie module and this is the new Enemy module:
local Enemy = {}
Enemy.__index = Enemy
function Enemy:new(hp, spd, dmg, mod)
local EnemyTable = setmetatable({}, Enemy)
EnemyTable.Health = hp
EnemyTable.Speed = spd
EnemyTable.Damage = dmg
EnemyTable.Model = mod
return EnemyTable
end
return Enemy
and here is the normal script:
local Enemy = require(script.Parent.Enemy)
local ZombModel = game.ReplicatedStorage.EnemyModels.ZombieModel
local Zombie = Enemy.new(100, 13, 20, ZombModel)
My only other question is should I move the model by just doing ZombModel.PrimaryPart.CFrame = CFrame.new()
or is their something else I should do?