Round System Help

Hello, I’m trying to figure out how to make a round system in Roblox. The problem is it only teleports one player to the match at a time. Heres an example to better visualize whats happening:

Suppose there are 2 players, A and B both in the lobby.

  • A gets teleported to the match, B is still in lobby
  • A comes back to the lobby
  • B gets teleported to the match, A is still in lobby
  • B comes back to the lobby

and it just contines like that.

local Players = game.Players
local fill = require(script:WaitForChild("LineFiller"))
local functions = require(game.ReplicatedStorage:WaitForChild("Functions"))
--local RoundInProgress, Winners = require(game.ReplicatedStorage:WaitForChild("Round"))
local RoundInProgress = false
local Intermission = 3 --Change to 20 when ready
local MaxPlayers = 0 --Change to 4 when ready
local RoundTime = 3 --Change to 120 when ready
local music = game.SoundService:WaitForChild("GameMusic")
local workspaceMaps = workspace.Maps:GetChildren()
local Winners = {}
local Maps = {}
local TimeLeft = script.TimeLeft

for _, map in pairs(workspaceMaps) do
	if map.Name ~= "Intro" then
		table.insert(Maps, map)
	end
end

while true do
	if #Players:GetPlayers() > MaxPlayers then
		for index, player in pairs(Players:GetPlayers()) do
			
			local char = player.Character or player.CharacterAdded:Wait()
			
			--Player Values
			local inIntro = player.PlayerValues:WaitForChild("isInIntroSequence")
			local inSelection = player.PlayerValues:WaitForChild("isInCharacterSelection")
			local Spawned = player.PlayerValues:WaitForChild("SpawnedIn")
			local inRound = player.PlayerValues:WaitForChild("inRound") --might not need
			local lost = player.PlayerValues:WaitForChild("lost") --might not need
			local canDash = player.PlayerActionValues:WaitForChild("CanDash")
			local canUseJutsu = player.PlayerActionValues:WaitForChild("canUseJutsu")
			local CanRun = player.PlayerActionValues:WaitForChild("CanRun")
			
			--Gui Variables
			local gui = player:WaitForChild("PlayerGui"):WaitForChild("Gamegui")
			local winnergui = player:WaitForChild("PlayerGui"):WaitForChild("Winner").WFrame
			local mapSelected = gui.MapSelected.MapName
			local timeRemaning = gui.TimeFrame.Time
			local winnerName = winnergui.WinnerName.Num
			local kills = winnergui.Kills.Num
			local rank = winnergui.Rank.Num
			local wins = winnergui.Wins.Num
			local white = winnergui.Parent.white
			
			--Other Variables
			local currentMap = nil
			local combat = player.Backpack.CombatHandler
			
			if Spawned.Value == true and RoundInProgress == false then
				table.insert(Winners, player)
				
				canDash.Value = false
				canUseJutsu.Value = false
				char.Humanoid.WalkSpeed = 16
				char.Humanoid.JumpPower = 50
				CanRun.Value = true
				combat.Disabled = true
				
				fill(timeRemaning, "INTERMISSION: ")
				for i = Intermission, 0, -1 do
					timeRemaning.Text = "INTERMISSION: "..i
					wait(1)
				end
				RoundInProgress = true
				
				currentMap = Maps[math.random(1, #Maps)]
				local spawns = currentMap.SPAWNS:GetChildren()
				
				local name = player.Name
				local check = workspace:FindFirstChild(name)
				if check then
					local checkHum = check:FindFirstChild("Humanoid")
					if checkHum then
						player.Character:MoveTo(spawns[index].Position)
						checkHum.WalkSpeed = 0
						checkHum.JumpPower = 0
						CanRun.Value = false
						canDash.Value = false
						combat.Disabled = true
					end
				end
				
				fill(mapSelected, currentMap.Name)
				
				for i = 3, 1, -1 do
					timeRemaning.Text = i
					wait(1)
				end
				timeRemaning.Text = "GO!"
				
				char.Humanoid.WalkSpeed = 16
				canDash.Value = true
				canUseJutsu.Value = true
				CanRun.Value = true
				char.Humanoid.JumpPower = 50
				combat.Disabled = false
				
				char.Humanoid.Died:Connect(function()
					table.remove(Winners, index)
					print(player.Name .. " has lost")
				end)

				wait(1)
				
				for i = RoundTime, 1, -1 do
					timeRemaning.Text = "Time Left: "..i
					TimeLeft.Value = i
					wait(1)
				end
				RoundInProgress = false
				
				char.Humanoid.WalkSpeed = 0
				canDash.Value = false
				canUseJutsu.Value = false
				char.Humanoid.JumpPower = 0
				CanRun.Value = false
				combat.Disabled = true
				
				fill(timeRemaning, "Time up!")
				wait(1)
				fill(timeRemaning, "Displaying Winners")
				wait(1)

				if next(Winners) ~= nil and player then
					gui.Enabled = false
					winnergui.Parent.Enabled = true
					gui.Parent.CharecterGui.Enabled = false
					
					local line = 1
					print("Number of winners: "..#Winners)
					while line <= #Winners do
						fill(winnerName, Winners[line].Name)
						print(line, Winners[line].Name)
						line = line + 1
						wait(2.5)
					end
				end
				
				for i, player in next, Winners do
					table.remove(Winners, i)
					print("resetting")
				end
				
				gui.Enabled = true
				winnergui.Parent.Enabled = false
				gui.Parent.CharecterGui.Enabled = true
				fill(timeRemaning, "Congrats Everyone!")
				wait(1)
				char:MoveTo(workspace.Lobby.SpawnLocation.Position)
				RoundInProgress = false
				
			elseif Spawned.Value == true and RoundInProgress == true then
				fill(mapSelected, currentMap.Name)
			end
		end
		
	else
		for _, player in next, game.Players:GetPlayers() do
			local gui = player:WaitForChild("PlayerGui"):WaitForChild("Gamegui")
			local timeRemaning = gui.TimeFrame.Time
			local mapSelected = gui.MapSelected.MapName
			mapSelected.Text = "NONE"
			timeRemaning.Text = "Waiting."
			wait(0.7)
			timeRemaning.Text = "Waiting.."
			wait(0.7)
			timeRemaning.Text = "Waiting..."
			wait(0.7)
		end
	end
	wait()
end

Heres the script if you see anything wrong. Thanks in advance!

So I think the problem is just that you are initiating the entire round synchronously, and all from inside the for loop too.

You should do the actual round-starting separately from preparing the players.

Everything beyond this line:


if Spawned.Value == true and RoundInProgress == false then

Should execute after the for loop is finished.

You need to fire remote events to the client to change the gui’s themselves instead of including it in a giant server script. Everything that has fill in it should be executed from a local script for starters.

Otherwise, things like canDash, canUseJutsu, changing the humanoid’s walkspeed and jumppower, connecting events to the humanoid, should be done from the server.

I know I was very sparse with what you have to do, so if you need help with how to do this, please ask here!

Can you give a small example of how it should look?

I would probably do something like this with your while true loop:

local Remote = --remote event

local PlayerVariables = {}
while true do
    local AllPlayers = Players:GetPlayers()
    if #AllPlayers > MaxPlayers then
        for _,player in ipairs(AllPlayers) do
            local char = player.Character
            if char then
                local vars = {}
                --put Player Variables in vars
                PlayerVariables[player.UserId] = vars
            end
        end
        local currentMap = nil
        local NumberSpawned = 0
        for _,vars in pairs(PlayerVariables) do
            if vars.Spawned == true then
                NumberSpawned = NumberSpawned + 1
            end
        end
        if NumberSpawned > MaxPlayers and RoundInProgress == false then
            for _,player in ipairs(AllPlayers) do
                -- set values and humanoid properties
            end
            Remote:FireAllClients("BeginIntermission",Intermission)
            wait(Intermission)
            
            RoundInProgress = true

            local currentMap = Maps[math.random(1, #Maps)]
            local spawns = currentMap.SPAWNS:GetChildren()
            for _,player in ipairs(AllPlayers) do
                if player.Character then
                    -- change the character's values
                end
            end
            Remote:FireAllClients("StartCountdown",3)
            wait(3)

            for _,player in ipairs(AllPlayers) do
                -- change properties with player.Character
            end
            Remote:FireAllClients("StartRound",RoundTime)

            wait(RoundTime)

            for _,players in ipairs(AllPlayers) do
                -- change player.Character properties
            end

            Remote:FireAllClients("EndRound",Winners)
            wait(#Winners * 2.5)
        end
        Winners = {}

        Remote:FireAllClients("RestartLoop")

        wait(1)
        for _, player in ipairs(AllPlayers) do
            if player.Character then
                player.Character:MoveTo(workspace.Lobby.SpawnLocation.Position)
            end
        end
    else
        Remote:FireAllClients("StillWaiting")
        wait(2.1)
    end
end

After you edit your while true loop, and write out all the stuff I pointed out with comments, you would have to handle the remote event client-side by changing Gui elements there.
e.g, in a LocalScript parented to your Gamegui presumably in StarterGui:

local gui = script.Parent
local winnergui = script.Parent.Parent:WaitForChild("Winner"):WaitForChild("WFrame")

-- this will require you to move LineFiller
local fill = require(script:WaitForChild("LineFiller")

local mapSelected = gui.MapSelected.MapName
local timeRemaning = gui.TimeFrame.Time
local winnerName = winnergui.WinnerName.Num
local kills = winnergui.Kills.Num
local rank = winnergui.Rank.Num
local wins = winnergui.Wins.Num
local white = winnergui.Parent.white

local Remote = -- the same remote event 
-- referenced in the server script

Remote.OnServerEvent:Connect(action, arg)
    if action == "BeginIntermission" then
        fill(timeRemaning, "INTERMISSION: ")
        for i = arg, 0, -1 do
            timeRemaning.Text = "INTERMISSION: " .. i
            wait(1)
        end
    elseif action == "StartCountdown" then
        for i = arg, 0, -1 do
            timeRemaning.Text = i
        end
    elseif action == "StartRound" then
        timeRemaning.Text = "GO!"
    elseif action == "EndRound"
        -- the rest of your gui actions
    elseif action == "RestartLoop" then
        
    end
end)

I didn’t fill everything in, but it should be very straightforward to figure out if you know what you’re doing.

1 Like

How should I display the winners? I was thinking to add all the players as winners add then table.remove the player when they lose. Is that a good system out should I change it?

Also I don’t really understand this part:

Can you explain it?

vars represents a default table for something that is assigned to players. PlayerVariables[player.UserId] = vars is intended to assign vars to a player.

https://www.lua.org/pil/2.5.html

That being said, you should read the code since the context for this is mostly in the code.

2 Likes

What I meant by put Player Variables in vars is putting this line:

In the vars table, so that you can use it in the server script.

And your method for keeping players in a table is good, you can just use AllPlayers to keep track of winners instead of a specific Winners table.
Just make sure to send the usernames of the players when you send them through the remote event, since instances can’t be sent through remotes.

2 Likes