How To Make A Round-Based System

Hello everyone! If you remember from my last tutorial I showed you guys how to make a Random Map Picker. In this tutorial I am going to show you how to make a Round-based system (this tutorial was asked for from @f1nneas).

(Quick note that there are many ways to make this system, this is my way)

The things that this system will do is:

1.) wait an intermission time
2.) pick a map from our random map picker
3.) sort the teams, one killer and the rest are survivors
4.) destroy the map and teleport the players back from our map picker
5.) repeat the steps 1-4

Intermission And Round Time

the first thing we want to do is figure out how long our round time and intermission time is going to be. In my case I made my intermission time 20 seconds and my round time 200 seconds. I have made two variables to help me know that this is either intermission time or round time in my script. when you are done with that we are going to want to make a variable that will let us know whether to skip the round or not just in case someone leaves and there are not enough players. Next we are going to want to set up the actual intermission time that will make sure there are enough players to play and set everything up for your game. Inside a while true do loop (so it continues forever), we will create a while loop that tells us how long to wait before starting the round, during this time we will constantly check to make sure there are enough players to play.

If there aren’t enough players we will wait until there are enough, here is how I set this up:

local roundtime = 200
local inter = 20

while true do
	local skip = false
	print("Inter")
	while inter > 0 do
		local ps = game.Players:GetPlayers()
		if #ps >= 2 then
			inter = inter - 1
			wait(1)
		else
			while #ps < 2 do
				ps = game.Players:GetPlayers()
				print("Need More")
				wait(1)
			end
			skip = true
			inter = 0
		end
	end
end

Now we will have to mess with the round time, in here we will have a while loop to tell if we are in a round or not just like the intermission. Before we do this though, we will have to check if the skip variable is set to false, meaning there was enough players. If it is we will continue through, otherwise we will reset everything and repeat the steps again.

I have set up my final result to look like this:

local roundtime = 200
local inter = 20

while true do
	local skip = false
	print("Inter")
	while inter > 0 do
		local ps = game.Players:GetPlayers()
		if #ps >= 2 then
			inter = inter - 1
			wait(1)
		else
			while #ps < 2 do
				ps = game.Players:GetPlayers()
				print("Need More")
				wait(1)
			end
			skip = true
			inter = 0
		end
	end
	wait(1)
	if skip == false then
		sortTeams()
		print("round")
		while roundtime > 0 do
			wait(1)
		end
	end
	print("not enough")
	skip = false
	inter = 20
	roundtime = 200
end

Sorting The Teams

Now we are going to have to set up the teams when the round starts, and bring everyone back to the lobby when the round is over. First make sure to define the teams game service at the top of your script, then in our sortTeams() function we will start by choosing and loading in the map from our Random Map Picker. Now we are going to define the players that are currently in the lobby, and everyone in general. Using the players in the lobby, lets pick one random person to be the Killer with math.random, we will also make sure to remove them from the table after this, so they can’t be picked again. Now we will get the remaining players and add them into the Survivor team using table.foreach and teleport them to the map.

My script looks like this:

local teams = game:GetService("Teams")
local roundtime = 200
local inter = 20

function sortTeams()
	chooseMap()
	loadMap()
	wait(3)
	local Players = game.Players:GetPlayers()
	local players = teams.Lobby:GetPlayers()
	
	-- Chooses Killer
	
	local index = math.random(1,#players) -- choose a random index between 1 and the length of the table
	players[index].Team = teams["Killer"] -- set the randomly chosen player to the Killer team
	table.remove(players,index) -- removes them from the pool of players, ensuring no duplicate picking later
		
	-- Sort Remaining Players
	
	table.foreach(players,function (_,player) player.Team = teams["Survivor"] end)
	teleportPlayers()
end

Finishing Up And Playing The Round

Now comes our final step, actually having the round play until either the killer leaves the game, there are no more survivors left, or the round time has hit 0. We are going to first create a local timer for the server to use just so nothing breaks or messes up and set the local timer to our roundtime. We will also make sure that the killer is still in the game by creating a variable called kactive and add the survivors in a table to make sure that they are still in the game. Once you have finished that, I added a wait(3) as a little stall and then set everyone back to the lobby using the general players variable and table.foreach. I then called the teleportBack() and deleteMap() function from the Random Map Picker and set the roundtime to 0 so everything could reset and start over again.

Here is how the final function turned out:

local teams = game:GetService("Teams")
local roundtime = 200
local inter = 20

function sortTeams()
	chooseMap()
	loadMap()
	wait(3)
	local Players = game.Players:GetPlayers()
	local players = teams.Lobby:GetPlayers()
	
	-- Chooses Killer
	
	local index = math.random(1,#players) -- choose a random index between 1 and the length of the table
	players[index].Team = teams["Killer"] -- set the randomly chosen player to the Killer team
	table.remove(players,index) -- removes them from the pool of players, ensuring no duplicate picking later
		
	-- Sort Remaining Players
	
	table.foreach(players,function (_,player) player.Team = teams["Survivor"] end)
	teleportPlayers()
	print("time")
	local localtimer = roundtime
	while localtimer > 0 do
		wait(1)
		localtimer = localtimer - 1
		local kactive = false
		local activepeople = {}
		for _, s in pairs(teams.Survivor:GetPlayers()) do
			if s then
				table.insert(activepeople, s)
			end
		end
		for _, k in pairs(teams.Killer:GetPlayers()) do
			if k then
				kactive = true
			end
		end
		if #activepeople < 1 then
			for _, k in pairs(teams.Killer:GetPlayers()) do
				-- k.Cash.Value = k.Cash.Value + 50
			end
			break
		end
		if not kactive then
			for _, s in pairs(teams.Survivor:GetPlayers()) do
				--s.Cash.Value = s.Cash.Value + 20
			end
			break
		end
		if localtimer == 0 then
			for _, s in pairs(teams.Survivor:GetPlayers()) do
				--s.Cash.Value = s.Cash.Value + 20
			end
		end
	end
			
	-- Back To Lobby
	
	roundtime = 0
	wait(3)
	teleportBack()
	deleteMap()
	table.foreach(Players,function (_,Player) Player.Team = teams["Lobby"] end)
end

Extra Information

table.foreach is deprecated, thx for letting me know @sjr04! use this for loop instead

for i, player in ipairs (players) do
    player.Team = teams["Survivor"]
end

This is a really big tutorial, if you had any trouble with this, make sure to let me know down below. If you have any thing that might make this better, please let me know below as well.

Here is the Random Map Picker tutorial I made: How To Make A Random Map Picker

If you want feel free to add in any extra things such as giving certain players cash if they win, I have added features such as that on this downloadable version if you are still having trouble or want to use those features: Round-Based System.rbxl (23.9 KB)

131 Likes

Hey everyone! I made a useful tutorial on this that may help you understand how to make this system better.

30 Likes

Thanks for the post.
How can we adjust the script so that the Killer and Survivors spawn to their respective
Spawn Locations?
(e.g. one spawn point for Killer, multiple spawn points for survivors).

6 Likes

Just make different spawnpoints for killer and survivors teams, you can see TeamColor property in it or something and just change it to the team you want.

1 Like

I did that, but the script calls for:

function teleportPlayers()
local players = game.Players:GetPlayers()
for i,v in pairs(players) do
v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).Spawn.CFrame
end
end

I’m new to scripting, so I’m assuming, in this case, I have to put something in the teleport function to link to the team spawns. ?

3 Likes

So where it calls this, “Spawn” would be the spawn point in the map, this would be where all the players are brought to when this function is called.

if you wanted to change the spawn for the killer, you would need to add a if statement to change the spawn area.

if v.Team == game.Teams.Killer then
    -- spawn for the killer
else
    -- spawn for the survivors
end
5 Likes

Thanks!
I was just looking into that.
I still don’t know what the scripting is to send the Killer to the specific team spawn though (digging through threads… nada) :frowning:

1 Like

So just add in the if statement to the function and if they are on the Killer team, change “Spawn” to the Killer Spawn and do the same with the survivors.

Glad I could help! :slightly_smiling_face:

2 Likes

How do I set the spawn to the team color spawn?

I don’t quite understand, like I said “Spawn” is the name of the spawn point for every player. If you have two separate spawns in the map (one for killer, other for survivors), change “Spawn” to your spawn name using the if statement.

Yeah, I’m super novice, so the quality of my queries can be lacking. :slight_smile: Sorry about that.

So for example, here is what I was just trying as a test to send players to the team spawns:

v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).SpawnLocation.TeamColor

Clearly this (“SpawnLocation.TeamColor”) is wrong, as no teleport occurs.

I see your problem, you are trying to move the player to a TeamColor, which isn’t possible, you need to use CFrame to get the player to the spawn.

Example:

local players = game.Players:GetPlayers()
for i, v in pairs (players) do
    if v.Team == game.Teams.Killer then
        v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).KillerSpawn.CFrame
    else
        v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).SurvivorSpawn.CFrame
    end
end

you can’t move a position (1,1,1) to a color (Grey)

3 Likes

That’s what I have been trying to figure out.
Seems so simple when you list it out… which tells me I really need to learn some basic computer science at minimum. :smiley:
Much appreciated!!!

1 Like

Bummer. Didn’t work for some reason. Here’s what I added:

function teleportPlayers()
local players = game.Players:GetPlayers()
for i, v in pairs (players) do
if v.Team == game.Teams.Killer then
v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).KillerSpawn.CFrame
else
v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).SurvivorSpawn.CFrame
end
end
end

Extra note guys! thx to @sjr04 for letting me know, table.foreach is deprecated. so instead of that one line, change it to this:

for i, player in ipairs(players) do
    player.Team = teams["Survivor"]
end

@JUDOBABY_PSL, make sure the players change to the team before you try to teleport them to the spawn, second make sure all spawn names and team names are spelled correctly.

2 Likes

Thanks! The names are all set correct.
Giving this a try now! :smiley:

So tenacious! :slight_smile:
I swapped the two “table.foreach(players,function (_,player) player.Team = teams[“Survivor”] end)” cases as suggested. Still doesn’t work.
Seems like it should be so simple, but, no go so far. I attached the file in case that’s easier to see where I’m going wrong. Greatly appreciate the help.

Round - Team Spawn.rbxl (27.9 KB)

Here’s the script:

> --[[
> 
> Round - Based System
> 
> Created By: HeIIo42bacon 
> 
> ]]--
> 
> 
> -- TERMS
> 
> local teams = game:GetService("Teams")
> local roundtime = 200
> local inter = 20
> local status = game.ReplicatedStorage:WaitForChild("Status")
> local maps = game.Lighting.Maps:GetChildren()
> local currentmap = workspace:WaitForChild("CurrentMap")
> local chosenmap = script:WaitForChild("ChosenMap")
> local spawner = workspace.Lobby.Spawn
> 
> -- MAP SYSTEM [MAKE SURE TO GRAB ANY OTHER NECESSARY THINGS FROM THE RANDOM MAP PICKER TUTORIAL]!
> 
> function chooseMap()
> 	local choices = {}
> 	for i = 1, #maps do
> 		if maps[i]:IsA("Model") then
> 			table.insert(choices, maps[i])
> 		end
> 	end
> 	local picked = math.random(1,#maps)
> 	chosenmap.Value = choices[picked].Name
> end
> 
> function loadMap()
> 	local map = game.Lighting.Maps:FindFirstChild(chosenmap.Value):Clone()
> 	map.Parent = currentmap
> 	--game.ReplicatedStorage.MapPicked:FireAllClients(chosenmap.Value) (text to tell the player what map it is)
> end
> 
> function deleteMap()
> 	for i,v in pairs(currentmap:GetChildren()) do
> 		if v:IsA("Model") then
> 			v:Destroy()
> 		end
> 	end
> end
> 
> function teleportPlayers()
> 	local players = game.Players:GetPlayers()
> 	for i, v in pairs (players) do
>     	if v.Team == game.Teams.Killer then
>         v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).KillerSpawn.CFrame
>     else
>         v.Character.HumanoidRootPart.CFrame = currentmap:FindFirstChild(chosenmap.Value).SurvivorSpawn.CFrame
> 	end   
>  end
> end
> 
> function teleportBack()
> 	local players = game.Players:GetPlayers()
> 	for i,v in pairs(players) do
> 		v.Character.HumanoidRootPart.CFrame = spawner.CFrame
> 	end
> end
> 
> -- TEAM SORTING
> 
> function sortTeams()
> 	chooseMap()
> 	loadMap()
> 	wait(3)
> 	local Players = game.Players:GetPlayers()
> 	local players = teams.Lobby:GetPlayers()
> 	
> 	-- Chooses Killer
> 	
> 	local index = math.random(1,#players) -- choose a random index between 1 and the length of the table
> 	players[index].Team = teams["Killer"] -- set the randomly chosen player to the Killer team
> 	table.remove(players,index) -- removes them from the pool of players, ensuring no duplicate picking later
> 		
> 	-- Sort Remaining Players
> 	
> 	for i, player in ipairs(players) do
>     player.Team = teams["Survivor"]
> 	end
> 	teleportPlayers()
> 	--game.ReplicatedStorage.timer:FireAllClients() (this is a timer for the players)
> 	print("time")
> 	local localtimer = roundtime
> 	while localtimer > 0 do
> 		wait(1)
> 		status.Value = localtimer
> 		localtimer = localtimer - 1
> 		local kactive = false
> 		local activepeople = {}
> 		for _, s in pairs(teams.Survivor:GetPlayers()) do
> 			if s then
> 				table.insert(activepeople, s)
> 			end
> 		end
> 		for _, k in pairs(teams.Killer:GetPlayers()) do
> 			if k then
> 				kactive = true
> 			end
> 		end
> 		if #activepeople < 1 then
> 			--game.ReplicatedStorage.Killer:FireAllClients() (this is a winners/losers text)
> 			status.Value = "Killer Wins!"
> 			for _, k in pairs(teams.Killer:GetPlayers()) do
> 				-- k.Cash.Value = k.Cash.Value + 50 (gives cash)
> 			end
> 			break
> 		end
> 		if not kactive then
> 			--game.ReplicatedStorage.Survivor:FireAllClients() (this is a winners/losers text)
> 			status.Value = "Survivors Win!"
> 			for _, s in pairs(teams.Survivor:GetPlayers()) do
> 				--s.Cash.Value = s.Cash.Value + 20 (gives cash)
> 			end
> 			break
> 		end
> 		if localtimer == 0 then
> 			status.Value = "Killer Win!"
> 			--game.ReplicatedStorage.Survivor:FireAllClients() (this is a winners/losers text)
> 			for _, s in pairs(teams.Survivor:GetPlayers()) do
> 				--s.Cash.Value = s.Cash.Value + 20 (gives cash)
> 			end
> 		end
> 	end
> 			
> 	-- Back To Lobby
> 	
> 	roundtime = 0
> 	wait(3)
> 	teleportBack()
> 	deleteMap()
> 	for i, player in ipairs(players) do
>     player.Team = teams["Lobby"]
> 	end
> end
> 
> -- MAIN FUNCTION
> 
> while true do
> 	local skip = false
> 	status.Value = ""
> 	print("Inter")
> 	--game.ReplicatedStorage.EnoughPlayers:FireAllClients() (gets rid of need more players text)
> 	--game.ReplicatedStorage.Inter:FireAllClients() (Intermission text) --- changing for >=1 to test
> 	while inter > 0 do
> 		local ps = game.Players:GetPlayers()
> 		if #ps >= 1 then
> 			status.Value = "Intermission For: "..inter
> 			inter = inter - 1
> 			wait(1)
> 		else
> 			while #ps < 1 do
> 				status.Value = "You Need 2 More Players To Play"
> 				ps = game.Players:GetPlayers()
> 				--game.ReplicatedStorage.NeedMorePlayers:FireAllClients() (tells the player they need more players to play)
> 				print("Need More")
> 				wait(1)
> 			end
> 			skip = true
> 			inter = 0
> 		end
> 	end
> 	wait(1)
> 	if skip == false then
> 		sortTeams()
> 		print("round")
> 		while roundtime > 0 do
> 			wait(1)
> 		end
> 	end
> 	print("not enough")
> 	skip = false
> 	inter = 20
> 	roundtime = 200
> end
1 Like

when I did the test, it worked perfectly fine for me, get rid of “>” sign because it will cause an error in your script. Other then that, again make sure all spawns and team names are spelled correctly.

Check the output too for any errors you need to fix

1 Like

Hmm… interesting.
Did you test it with two players in Roblox?
When I do that, teams are assigned, timer counts down to 1, the map is loaded, but the players do not teleport from the lobby.
???

yes, you have to test it with two players. look in your output to see if you find any errors.

1 Like