function Module:NewBoid(Origin, Environment)
local NewBoid = setmetatable(Classes.Boid, {})
NewBoid.Environment = Environment
NewBoid.Body = Templates.Body:Clone();
NewBoid.Speed = 1;
NewBoid.Range = 15;
NewBoid.Fov = 0.5;
NewBoid.Enabled = true;
-- Body
NewBoid.Body.Parent = NewBoid.Environment
NewBoid.Body.Position = Origin
return NewBoid
end
function Classes.Boid:Update()
local LookDirection = self.Body.CFrame.LookVector
local BoidsInRange = {}
for BoidI, Boid in pairs(self.Environment:GetChildren()) do
if Boid:IsA("BasePart") then
local Sub = Boid.Position - self.Body.Position
local Distance = Sub.Magnitude
local LookDot = LookDirection:Dot(Boid.CFrame.LookVector)
if Distance <= self.Range and LookDot > self.Fov then
table.insert(BoidsInRange, Boid)
end
end
end
for BoidI, Boid in pairs(BoidsInRange) do
local Sub = Boid.Position - self.Body.Position
local Distance = Sub.Magnitude
local Ratio = math.clamp(Distance / 4, 0, 1)
LookDirection -= Ratio * Sub
end
self.Body.Position += (LookDirection / 4) * self.Speed
self.Body.CFrame = CFrame.lookAt(self.Body.Position, self.Body.Position + LookDirection)
end
function Classes.Boid:Destroy()
self.Body:Destroy();
self.Range = nil;
self.Enabled = nil;
self = nil
end
return Module
If you can’t tell, I am trying to simulate boids/birds, It’s not finished though.
I think you got the parameters mixed up. The first parameter should be the table you are setting the metatable of, and the second parameter is what to set the metatable to.
you’re setting the metatable the wrong way round, it should be table you want to give a metatable to, and then the metatable you are going to give to that table
local BaseModule = script
local Module = {}
local Classes = {
Boid = {};
}
-- Services
local WorkService = game:GetService("Workspace")
local RunService = game:GetService("RunService")
-- Local
local Templates = BaseModule.Templates
-- Boid Class
function Module:NewBoid(Origin, Environment)
local NewBoid = setmetatable(Classes.Boid, {})
NewBoid.Environment = Environment
NewBoid.Body = Templates.Body:Clone();
NewBoid.Speed = 1;
NewBoid.Range = 15;
NewBoid.Fov = 0.5;
NewBoid.Enabled = true;
-- Body
NewBoid.Body.Parent = NewBoid.Environment
NewBoid.Body.Position = Origin
return NewBoid
end
function Classes.Boid:Update()
local LookDirection = self.Body.CFrame.LookVector
local BoidsInRange = {}
for BoidI, Boid in pairs(self.Environment:GetChildren()) do
if Boid:IsA("BasePart") then
local Sub = Boid.Position - self.Body.Position
local Distance = Sub.Magnitude
local LookDot = LookDirection:Dot(Boid.CFrame.LookVector)
if Distance <= self.Range and LookDot > self.Fov then
table.insert(BoidsInRange, Boid)
end
end
end
for BoidI, Boid in pairs(BoidsInRange) do
local Sub = Boid.Position - self.Body.Position
local Distance = Sub.Magnitude
local Ratio = math.clamp(Distance / 4, 0, 1)
LookDirection -= Ratio * Sub
end
self.Body.Position += (LookDirection / 4) * self.Speed
self.Body.CFrame = CFrame.lookAt(self.Body.Position, self.Body.Position + LookDirection)
end
function Classes.Boid:Destroy()
self.Body:Destroy();
self.Range = nil;
self.Enabled = nil;
self = nil
end
return Module
I don’t see you using any metamethods, so what do you mean by “methods don’t work”? You might need to define subprograms within the class:
local class = {
["Function1"] = function()
end
}
but you also only have one class, so I don’t understand your Classes table at the top. Seperate classes should use seperate modules.
local boid = {}
boid.__index = boid
boid.__newindex = function(tbl, key, value)
if rawlen(tbl) < 15 then
rawset(tbl, key, value)
else
warn("New indexes are not allowed.")
end
end
function Boid:MethodOne()
--do stuff
end
Also, the correct syntax of setmetatable is as follows:
Parameter One is the table having its metatable set. This parameter is also returned.
Parameter Two is the table to assign as metatable to Parameter One. Parameter One will inherit everything from it, including metamethods.
local something = {}
function something.hi()
end
local self = setmetatable({}, something)
print(self) --> {["hi"] = "function"}
Sorry, I really don’t understand metatables very well, I am not sure what meta methods are.
But I am pretty sure that I am using meta methods in this, like for example I have a method called “Update” that updates the boid’s position, isn’t that a method?
I know I am only using one class but the classes table just makes things more organized, also I don’t understand why every class has to be in a different module, can you explain please?
I tried searching up about metatables and what they do but all I saw was that meta tables are just fancy tables which was very confusing.
The classes table is pointless if there is only one class. All your other classes (not Boid) should be in different modules - the whole point in an Object-Oriented approach (which we are doing) is to simplify and declutter code. Multiple classes per script means the code becomes more cluttered.
local BaseModule = script
local Module = {}
-- Services
local WorkService = game:GetService("Workspace")
local RunService = game:GetService("RunService")
-- Local
local Templates = BaseModule.Templates
-- Boid Module
function Module:New(Origin, Environment)
local NewBoid = setmetatable({}, Module)
NewBoid.__index = NewBoid
NewBoid.Environment = Environment
NewBoid.Body = Templates.Body:Clone();
NewBoid.Speed = 1;
NewBoid.Range = 15;
NewBoid.Fov = 0.5;
NewBoid.Enabled = true;
-- Body
NewBoid.Body.Parent = NewBoid.Environment
NewBoid.Body.Position = Origin
return NewBoid
end
function Module.Update(self)
local LookDirection = self.Body.CFrame.LookVector
local BoidsInRange = {}
for BoidI, Boid in pairs(self.Environment:GetChildren()) do
if Boid:IsA("BasePart") then
local Sub = Boid.Position - self.Body.Position
local Distance = Sub.Magnitude
local LookDot = LookDirection:Dot(Boid.CFrame.LookVector)
if Distance <= self.Range and LookDot > self.Fov then
table.insert(BoidsInRange, Boid)
end
end
end
for BoidI, Boid in pairs(BoidsInRange) do
local Sub = Boid.Position - self.Body.Position
local Distance = Sub.Magnitude
local Ratio = math.clamp(Distance / 4, 0, 1)
LookDirection -= Ratio * Sub
end
self.Body.Position += (LookDirection / 4) * self.Speed
self.Body.CFrame = CFrame.lookAt(self.Body.Position, self.Body.Position + LookDirection)
end
function Module.Destroy(self)
self.Body:Destroy();
self.Range = nil;
self.Enabled = nil;
self = nil
end
return Module
From what I know, self is a variable that returns the table of a function.
For example:
local TestTable = {}
TestTable.Value = 5
function TestTable:Print() -- The self variable in this function is TestTable.
print(self.Value) -- Should print 5.
end