Alright, I’m in the process of refactoring my game in Roblox and I’m learning about Object-Oriented Programming because it’s the kind of programming I want to master and perfect to it’s maximum level because it’s a cool way to organize the code and I’m dealing with a cyclic dependency problem in which I’m creating a main module GameMode which will have all the function that other child like FallMode, ColorMode, ParkourMode will inherit of. However, for each game mode the game run its own way which makes the situation a little bit more tricky in terms of architecture design so basically here’s the issue
I need GameMode for the module child which will inherit the parents method but at the same time I need the child module to run the gamemode its own way which makes it a very annoying situation
Here’s the code of GameMode and FallMode
Edit : From my research there’s a solution called the Mediator Pattern to remedy this situation but I don’t know how I would implement it on this solution
GameMode :
-- SERVICES
local ServerStorageService = game:GetService("ServerStorage")
local ReplicatedStorageService = game:GetService("ReplicatedStorage")
local PlayerService = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
-- FOLDERS
local MatchRemoteEvents = ReplicatedStorageService:WaitForChild("RemoteEvents"):WaitForChild("Match")
local ScriptsServerScripts = ServerScriptService:WaitForChild("Scripts")
-- EVENTS
local MatchGetScoreEvent = MatchRemoteEvents:WaitForChild("MatchGetScoreEvent")
-- VARIABLES
local Maps = ServerStorageService:WaitForChild("Assets"):WaitForChild("Maps")
local SpawnPoint = game.Workspace.SpawnLocation
-- MODULE
local FallMode = require(ScriptsServerScripts.GameMode.FallMode)
local GameMode = {}
-----------------------------------------------------------------------
-- --
-- FUNCTION THAT HANDLE GAME MODE START --
-- --
-----------------------------------------------------------------------
function GameMode:StartGame(modeChoosen: Instance)
local mapChoosen = Maps:FindFirstChild(modeChoosen)
if not mapChoosen then
warn("Map not found: ", modeChoosen)
return
end
self.mapChoosen = Maps:WaitForChild(modeChoosen):Clone()
self.mapChoosen.Parent = game.Workspace
local function selectRandomSpawn()
local spawnPoints = self.mapChoosen:FindFirstChild("Spawns"):GetChildren()
local spawnPart
repeat
local randomIndex = math.random(1, #spawnPoints)
spawnPart = spawnPoints[randomIndex]
until not spawnPart:GetAttribute("isOccupied")
spawnPart:SetAttribute("isOccupied", true)
return spawnPart
end
for _, player in ipairs(PlayerService:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local spawnPart = selectRandomSpawn()
player.Character.HumanoidRootPart.CFrame = spawnPart.CFrame
player.Character.HumanoidRootPart.Anchored = true
end
end
task.wait(3)
self.participants = {}
self.timeSinceGameStarted = os.clock()
for _, player in ipairs(PlayerService:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
player.Character.HumanoidRootPart.Anchored = false
self.participants[player] = {isAlive = true, survivalTime = 0}
end
end
print(self)
end
-----------------------------------------------------------------------
-- --
-- FUNCTION THAT HANDLE GAME MODE ENDING --
-- --
-----------------------------------------------------------------------
function GameMode:EndGame()
self:GetFinalScores()
self.mapChoosen:Destroy()
end
-----------------------------------------------------------------------
-- --
-- FUNCTION THAT HANDLE THE SCORES AT THE END OF THE GAME --
-- --
-----------------------------------------------------------------------
function GameMode:GetFinalScores()
self.scores = {}
for player, data in pairs(self.participants) do
table.insert(self.scores, {player = player, survivalTime = data.survivalTime})
end
table.sort(self.scores, function(a, b)
return a.survivalTime > b.survivalTime
end)
if #self.scores > 0 then
for rank, entry in ipairs(self.scores) do
MatchGetScoreEvent:FireClient(entry.player, rank, entry.survivalTime, self.mapChoosen.Name)
end
else
end
end
function GameMode:ManageEliminations(player)
if self.participants[player] then
self.participants[player].isAlive = false
self.participants[player].survivalTime = os.clock() - self.timeSinceGameStarted
end
local aliveCount = 0
local lastParticipant = nil
for participant, data in pairs(self.participants) do
if data.isAlive then
aliveCount = aliveCount + 1
lastParticipant = participant
end
end
if aliveCount == 1 then
if lastParticipant and lastParticipant.Character and lastParticipant.Character:FindFirstChild("HumanoidRootPart") then
self.participants[lastParticipant].isAlive = false
self.participants[lastParticipant].survivalTime = os.clock() - self.timeSinceGameStarted
lastParticipant.Character.HumanoidRootPart.CFrame = SpawnPoint.CFrame
end
self:EndGame()
elseif aliveCount == 0 then
self:EndGame()
end
end
return GameMode
FallMode :
-- SERVICES
local ServerScriptService = game:GetService("ServerScriptService")
local TweenService = game:GetService("TweenService")
local PlayerService = game:GetService("Players")
-- FOLDERS
local ScriptsServerScript = ServerScriptService:WaitForChild("Scripts")
-- MODULE
local GameMode = require(ScriptsServerScript.GameMode)
local FallMode = {}
FallMode.__index = FallMode
setmetatable(FallMode, GameMode)
function FallMode:runGame()
local magma = self.mapChoosen:FindFirstChild("Magma")
if magma then
magma.Touched:Connect(function(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
local Player = PlayerService:GetPlayerFromCharacter(hit.Parent)
if humanoid and not self.debouncePlayers[Player] then
self.debouncePlayers[Player] = true
humanoid.Health = 0
self:removeParticipants(Player)
end
end)
end
local debounce = {}
for i, v in ipairs(self.mapChoosen:GetDescendants()) do
if v:IsA("MeshPart") and not v:IsA("Part") then
v.Touched:Connect(function(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if humanoid and not debounce[v] then
debounce[v] = true
local tween
if v.Parent ~= nil then
if v.Parent.Name == "Stage1" then
tween = TweenService:Create(v, TweenInfo.new(1.28), { Transparency = 1 })
elseif v.Parent.Name == "Stage2" then
tween = TweenService:Create(v, TweenInfo.new(0.98), { Transparency = 1 })
elseif v.Parent.Name == "Stage3" then
tween = TweenService:Create(v, TweenInfo.new(0.58), { Transparency = 1 })
elseif v.Parent.Name == "Stage4" then
tween = TweenService:Create(v, TweenInfo.new(0.58), { Transparency = 1 })
elseif v.Parent.Name == "Stage5" then
tween = TweenService:Create(v, TweenInfo.new(0.58), { Transparency = 1 })
else
tween = TweenService:Create(v, TweenInfo.new(1.28), { Transparency = 1 })
end
end
if tween ~= nil then
tween:Play()
tween.Completed:Connect(function()
v:Destroy()
debounce[v] = nil
end)
end
end
end)
end
end
end
return FallMode