These modules are for a task system, where “Tasks” are objects that hold data such as associated players and child objectives, while “Objectives” are objects that manage actually progressing through a task.
Task.lua (Class)
local Task = {}
local Signal = require(game:GetService("ReplicatedStorage").Utils.Signal)
function Task.new(callback: (any) -> (any)?)
local self = {}
-- Properties
self.Name = "Task"
self.IsCompleted = false
self._Callback = callback or nil
self._Objectives = {}
self.Players = {}
-- Events
self.Changed = Signal.new()
self.Completed = Signal.new()
local proxy = setmetatable({}, {
__index = function(_, key)
return self[key] or Task[key]
end,
__newindex = function(_, key, value)
if self[key] ~= value then
self[key] = value
self.Changed:Fire(key, value)
end
end
})
return proxy
end
function Task:GetName(): string
return self.Name
end
function Task:AddPlayer(player: Player)
table.insert(self.Players, player)
end
function Task:RemovePlayer(player: Player)
for i, v in pairs(self.Players) do
if v == player then
table.remove(self.Players, i)
end
end
end
function Task:GetObjectives(): {any}
return self._Objectives
end
function Task:ClearAllObjectives()
for _, objective in pairs(self._Objectives) do
objective:Destroy()
end
end
function Task:Complete(priorityPlayer: Player?)
assert(not self.IsCompleted, "This task is already completed")
self.IsCompleted = true
self.Completed:Fire(self:GetPlayers(), priorityPlayer)
if self._Callback then
self._Callback(self:GetPlayers(), priorityPlayer)
end
end
function Task:Destroy()
self:ClearAllObjectives()
self.Changed:Destroy()
self.Completed:Destroy()
self = nil
end
return Task
Objective.lua (DataType)
local Objective = {}
Objective.__index = Objective
type ObjectiveType =
"CollectItems"
function Objective.new(objectiveType: ObjectiveType, ...)
assert(script:FindFirstChild(objectiveType), "Could not find objective of that type")
return require(script:FindFirstChild(objectiveType)).new(...)
end
return Objective
BaseObjective.lua (Class)
local Objective = {}
local Signal = require(game:GetService("ReplicatedStorage").Utils.Signal)
function Objective.new(callback: (any) -> any?)
local self = {}
-- Properties
self.Name = "Objective"
self.Text = "Complete This Objective"
self.IsCompleted = false
self._Callback = callback or nil
self.Parent = nil
-- Events
self.Changed = Signal.new()
self.AncestryChanged = Signal.new()
self.Completed = Signal.new()
local proxy = setmetatable({}, {
__index = function(_, key)
return self[key] or Objective[key]
end,
__newindex = function(_, key, value)
if self[key] ~= value then
self[key] = value
self.Changed:Fire(key, value)
if tostring(key) == "Parent" then
self.AncestryChanged:Fire(value)
self.Parent[self.Name] = self
end
end
end
})
return proxy
end
function Objective:GetText(): string
return self.Text
end
function Objective:IsDescendantOf(task: {any}): boolean
return self.Parent == task
end
function Objective:Complete(priorityPlayer: Player?)
assert(self.IsCompleted, "This objective is already completed")
self.IsCompleted = true
self.Completed:Fire(self.Parent and self.Parent:GetPlayers() or {}, priorityPlayer)
if self._Callback then
self._Callback(self.Parent and self.Parent:GetPlayers() or {}, priorityPlayer)
end
end
function Objective:Destroy()
self.Changed:Destroy()
self.AncestryChanged:Destroy()
self.Completed:Destroy()
self = nil
end
return Objective
local taskCallback = function() print("Completed task!") end
local newTask = Task.new(taskCallback)
newTask.Name = "Task"
newTask:AddPlayer(game.Players.Galicate)
local objectiveCallback = function() print("Completed objective!") end
local newObjective = Objective.new("CollectItems", objectiveCallback)
newObjective.Items = {"Item1", "Item2", "Item3"}
newObjective.Text = "Collect 3 items"
newObjective.Parent = newTask