How to use OOP/metatables with entities?

How would I use metatables to create entities and simulate their AIs? To my knowledge, other OOP languages usually have a .__process function to something similar which gets called each frame, and which I think would be the best way to program AI, unless there is a better way.

In a module script I have:

local EntityClass= {}
EntityClass.__index = EntityClass

	local instance = setmetatable({},EntityClass)
	return instance

-- creates a body for the entity
function EntityClass:CreateBody(entityId,pos)
	local entity = game.ServerStorage.Entities[entityId]:Clone()
	entity.Position = pos
	entity.Parent = workspace

	self.body = entity

	return entity

-- How would I simulate entity Ai?

return EntityClass

Some additional question about OOP I have:

  • I plan to have dozens of different types of entities. Do I make a class and a module for each type of entity that inherits from the entity class? Or is there a more efficient way to do it?
  • If I want to, for example, hit an enemy and apply damage to an entity, how would I call a function that is inside the EntityClass that handles damage?

Thanks all!

1 Like

I’d probably say just make a function in the module to handle damage, etc. and call it with the appropriate entity, because the entity itself will inherit these functions so they can be called with the entity itself.

For the AI, you could even use a seperate script. Or, just use a procedure in your current module.

function EntityClass.TakeDamage(entity, damage)
    --stuff goes here

function EntityClass.MoveEntity(entity)
    --movement code could go here

    local self = setmetatable({}, EntityClass)
    task.spawn(self.MoveEntity, entity)

Also yes, you should probably make a new class for each entity. It’d help to simplify the overall system.

I hope this helps :smiley: .

(I have later realised that parameters are not the best idea for this. It will inherit, so the function should be called with itself. for the sake of readability here, I made a quick type for the entity).

function EntityClass:TakeDamage()
    --stuff goes here

function EntityClass:MoveEntity()
    --stuff goes here

    local self:Entity = setmetatable({}, EntityClass)
    return self

export type Entity = {
    ["Damage"]: (Entity) -> (nil),
    ["MoveEntity"]: (Entity) -> (nil),
    ["new"]: (nil) -> (Entity)

Then, outside the script:

local Entity:module.Entity =
task.spawn(Entity.TakeDamage, Entity)
task.spawn(Entity.MoveEntity, Entity)

So I would have a script that handles where the entities are created, and give them a unique identifier so you know which entity is which.

--@@ Creating Entities
local Entities: { [string]: table } = {}

--> Creation:
local UniqueID = --> Can use a custom method or just HttpService:GenerateGUID()
local Entity =

Entities[UniqueID] = Entity 

Now whenever you want to access this specific entity you could just use the unique id to do so.

As for taking damage that is pretty straightforward, in the script that handles the creation of the entity you would add a damage function and also add a damage function to the entity class itself.

local function attackEntity(uniqueID: string, damage: number)
   local Entity = Entities[uniqueID]
   if not Entity then


How the class would look:

	local self = setmetatable({}, EntityClass)
    self.Health = 100
	return self

--@@ Deals damage to entity
function EntityClass:Damage(damage: number)
   self.Health -= damage

Finally the actual movement, there is so many ways to do this. One way is you could handle it all in the class itself, using pathfinding or any custom path you have and just have them move in a function, or you could use runservice to loop through all entities and move them accordingly. I haven’t really used entities in this way so I wouldn’t know the most optimised approach but you can always try them and see which one performs better.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.