First time trying to write the oop style module here
is there a way to remove the exisiting table from the metatable once the character is dead?
I’d imagine leaving them there after the character no longer exist might cause the memory leak issue
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SimplePath = require(ReplicatedStorage.Modules.SimplePath)
local Wanderer = {}
Wanderer.__index = Wanderer
function Wanderer.new(char:Model)
local self = setmetatable({}, Wanderer)
self.AI = char
self.Cooldown = 5
self.Health = 20
self.Speed = 10
local Hum = char:WaitForChild("Humanoid")
Hum.WalkSpeed = self.Speed
Hum.MaxHealth = self.Health
Hum.Health = Hum.MaxHealth
if self.AI.PrimaryPart ~= nil then
self.AI.PrimaryPart:SetNetworkOwner(nil)
end
return self
end
function SelectNode(NodesFolder:Folder)
return NodesFolder:GetChildren()[math.random(1, #NodesFolder:GetChildren())]
end
function Wanderer:Remove()
-- ???
end
function Wanderer:Start()
if self.AI.PrimaryPart == nil then return end
local Target = SelectNode(workspace.PathNodes)
local Path = SimplePath.new(self.AI)
Path.Visualize = true
Path.Blocked:Connect(function()
Path:Run(Target)
end)
Path.WaypointReached:Connect(function()
Path:Run(Target)
end)
Path.Error:Connect(function(errorType)
Path:Run(Target)
end)
Path.Reached:Connect(function()
task.wait(self.Cooldown)
self:Start()
end)
Path:Run(Target)
end
return Wanderer
Yes, having instances tied to a table will most likely prevent it from being GCed.
I highly recommend using ECS over OOP since such situations almost never happen and don’t force you to look at Luau Heap for debugging, and it gives direct access to integrate functional programming with ECS.
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SimplePath = require(ReplicatedStorage.Modules.SimplePath)
local PathNodes = workspace.PathNodes
local Wanderer = {}
Wanderer.__index = Wanderer
type Wanderer_Data = {
AI:Model;
Cooldown:number;
Health:number;
Speed:number;
}
type Wanderer = setmetatable<Wanderer_Data,typeof(Wanderer)>
local function SelectNode(NodesFolder:Folder)
return NodesFolder:GetChildren()[math.random(1, #NodesFolder:GetChildren())]
end
function Wanderer:Remove()
-- ???
end
function Wanderer:Start()
if self.AI.PrimaryPart == nil then return end
local Target = SelectNode(PathNodes)
local Path = SimplePath.new(self.AI)
Path.Visualize = true
Path.Blocked:Connect(function()
Path:Run(Target)
end)
Path.WaypointReached:Connect(function()
Path:Run(Target)
end)
Path.Error:Connect(function(errorType)
Path:Run(Target)
end)
Path.Reached:Connect(function()
task.wait(self.Cooldown)
self:Start()
end)
Path:Run(Target)
end
return function(char:Model):Wanderer
local self = {
AI = char;
Cooldown = 5;
Health = 20;
Speed = 10;
}::Wanderer_Data
local Hum = char:WaitForChild("Humanoid")::Humanoid
Hum.WalkSpeed = 10
Hum.MaxHealth = 20
Hum.Health = 20
if char.PrimaryPart then
char.PrimaryPart:SetNetworkOwner(nil)
end
Hum.Died:Once(function():()
table.clear(self::any)
end)
return setmetatable(self,Wanderer)::Wanderer
end