How To Make A Random Map Picker

Hello guys in this tutorial I plan on teaching you how to make a successful random map picking script which will do the following:

1.) choose a random map
2.) load the random map
3.) teleport all of the players to a certain spot on the map and back
4.) destroy the map when finished
5.) repeat the cycle of steps 1-4

Getting Started

The first thing we are going to want to do is of course make our maps, when you are done with them make sure to group all of them and call the model “Maps.” (Make sure to make a lobby in Workspace) it doesn’t have to be a model, you may make it a folder as well, but make sure to parent the model/folder to ServerStorage. In those maps make sure to add a part and name it “Spawn,” this will be where we want the character to spawn on the map. Next you will want to add a folder into workspace and name it “CurrentMap.” Finally the last thing we need to make is to add a (Server)Script in ServerScriptService and add a StringValue named “ChosenMap” as a child of that script. At the end of this your set up should look like this:

Random Map Picker - Roblox Studio 2_19_2020 7_31_40 PM

Now that your set up is all done, we can start getting into the main part you guys probably wanted to know, the actual script.

First thing we are going to put into our script is to define all of the necessary things needed to make this script work, so that way it is easier and cleaner. Make sure you define the maps, currentmap folder, chosenmap stringvalue, and our spawn back to the lobby. As for players, we will need to define them in our teleport function, so that way it can grab everyone appropriately. When you are done your script should end up like this:

local maps = game.ServerStorage.Maps:GetChildren()
local currentmap = workspace:WaitForChild("CurrentMap")
local chosenmap = script:WaitForChild("ChosenMap")
local spawner = workspace.Lobby:WaitForChild("Spawn") -- match this to your path of your lobby spawner

Messing With The Maps

Now that we have finished defining everything, lets get into our map chooser, this will choose a random map and save its name to the stringvalue we have called “ChosenMap.” In this we are going to create a function and name it chooseMap(), in this function we will use a for loop to look at all of the maps we have in ServerStorage then adding it to a table and checking to see if it is a model just in case. After we have added all of the maps to the table, we will pick a random one using math.random and set our stringvalue to the name of that map. This is how I set up my function:

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

Next we need to actually load the map into workspace and then delete it when the round is over. I am pretty sure you know what we are going to do for loading the map, yep we are going to clone it into our “CurrentMap” folder by using the value in our “ChosenMap” stringvalue. As for deleting the map we simply search for our “CurrentMap’s” folder and if it is a model, that being our current map, we will destroy it. Here is how I set this up:

function loadMap()
	local map = game.ServerStorage.Maps:FindFirstChild(chosenmap.Value):Clone()
	map.Parent = currentmap
end

function deleteMap()
	for i,v in pairs(currentmap:GetChildren()) do
		if v:IsA("Model") then
			v:Destroy()
		end
	end
end

Teleporting The Players And Finishing Everything Up

Now here comes probably the hardest part of this script, teleporting the players to the map and back. This is, as I have said up top, where we will need to define all of the players in the server. When teleporting the player you can use MoveTo() for their character, but I feel it is just easier to find the HumanoidRootPart and set its CFrame to our spawns CFrame on the map that has been chosen. When we are teleporting the player back, it is the same thing, except always having the HumanoidRootPart’s CFrame change to the spawn’s CFrame in the lobby. Here is how I set this up:

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

function teleportBack()
	local players = game.Players:GetPlayers()
	for i,v in pairs(players) do
		v.Character.HumanoidRootPart.CFrame = spawner.CFrame
	end
end

Now that all of our functions are set up, we need to call them at the correct time for the script to actually work. We will make a while loop so the script will repeatedly run and in this set the times we want the functions to be called. Change this to your set up, mine is probably different then what yours will be:

while true do
    wait(5)
    chooseMap()
    loadMap()
    wait(1)
    teleportPlayers()
    wait(20)
    teleportBack()
    deleteMap()
end

Extras

I hope this long tutorial was helpful! If you had a hard time trying to understand some things or had a hard time creating this script, you can take a look at this downloadable file so you can look over and review it: Random Map Picker.rbxl (22.4 KB)

Thanks For Reading I Hope This Was Helpful! :grin:

107 Likes

FYI: In math.random you can give one argument and it’ll produce a number between [1, n]

For example:

local picked = math.random(#maps)

Nice tutorial anywho.

8 Likes

Adding onto what @ReturnedTrue said, you can just index from the choices table instead of using local picked = math.random(1,#maps).

    local picked = choices[math.random(#maps)]
    chosenmap.Value = picked.Name
8 Likes

Based on my previous mistakes and some posts that I’ve read - I would like to advice to load bigger maps piece by piece, otherwise it’ll lag the server for a moment. Referring to How should I handle loading maps? - #4 by Cartoon_Corpze

Like so:


local ServerStorage        = game:GetService("ServerStorage")
local MapsFolder           = ServerStorage.Maps


---//Choose map function 
local ChosenMap            = MapsFolder[math.random(#MapsFolder)]


function loadMap()
--//Send the clients a message that the map is loading (Perhaps a notification UI?)
          for Index, Part in pairs(Chosenmap:GetChildren()) do 
            v:Clone().Parent = workspace.CurrentMap --//Assuming you have a CurrentMap folder in the workspace
            task.wait(.1)
          end
--//Send the clients a message that the map is ready
end

Also I’d use the event :ClearAllChildren() for the map removal

5 Likes

Thanks for the tutorial! It was very helpful. But can you do a tutorial for making a round-based system? Would be appreciated if you do, thanks!

3 Likes

While using a random value between 1 and n is the correct thinking, math.random tends to have pretty bad results if using for something you want to actually appear a little random. I recommend that you use the Random object.

The Random datatype and math.random have no difference in randomness, they’re both psuedorandom and use the same algorithm.

The only difference is that the Random datatype has it’s own seed per object (since math.randomseed sets it for the entire environment) and that it has functions such as NextNumber/NextInteger.

The Random datatype is great to use, but it isn’t any more random than math.random.

4 Likes

It doesn’t make any sense to yield for so long, especially in the case you are considering (huge maps). For instance, loading a 15,000 parts map would take at least 25 minutes to load, while if you just insert it as a whole could take up to only a few seconds (maybe a minute in very low-end devices if it included large parts or unanchored components).

Also, @HeIIo42bacon, excellent tutorial! I think you explained it so well. Loading maps is essential for a lot of places and genres, so this topic will be for sure very useful for many devs!

I think you could add that changing HumanoidRootPart’s CFrame will overwrite the character’s rotation, while MoveTo will conserve it. This detail might be useful for some gamemodes.

But again, thanks for your contribution!

2 Likes

there are a lot of ways to perform this type of thing but I’d say this is a pretty decent tutorial, good job!

I sometimes get repetitive behavior from calls to math.random so I usually do something like this:

local Maps = { --[[ maps ]] }
local RandInstance = Random.new()

function GetRandomMap(MapsTable, RandomIndex)
     return MapsTable[RandomIndex]
end

GetRandomMap(Maps, RandInstance:NextInteger(0, #Maps)) -- Call on Maps table w/ random index between 0 and length of table
2 Likes

Decrease the wait to your liking and tailor it to your game. The whole reply was focused on advising against instantaneous map loading. I sent a link to the post that explains (specifically the reply section) the reason why that is a bad idea, have a read.

2 Likes

You could make this a lot more efficient by picking the map straight from the Maps in ServerStorage. Using recursion, you can also make sure that the map that got picked isn’t the same map as the last map.

local maps = game.ServerStorage.Maps:GetChildren()
local lastMap = nil

function chooseMap()
  local picked = maps[math.random(1,#maps)
  if picked.Name == lastMap then return chooseMap() end
  chosenmap.Value = picked.Name
  lastMap = picked.Name
end
6 Likes

Hey everyone! Thanks for all of the feedback you gave on how to improve this script! I have made a video tutorial that combines some of your ideas together. You can check it out here:

Sorry if this video was a little hard to understand, I messed some things up a bit and kind of wasn’t thinking well that day lol. Anyways enjoy, I hoped this helps! :slightly_smiling_face:

Edit: Also I don’t know if I should set this as a solution, I have seen some people do that, but I feel as if it is not right. Tell me if it is appropriate to solution this though for the tutorial and I will.

7 Likes

I just realised how bad my scripted game cycle is. Amazing tutorial. You made it look easy and cool. Keep it up!

I’m not sure if this is necrobumping, but can you please add a timer so players can see how long it will take before a round ends/starts?

You should check out my other tutorial for that where it fully teaches you how to make a round-based system. It should show you how to set a timer up in there.

Hey Guys, so I am very new to scripting and stuff. I have a map with JTOH [jukes towers of hell] client objects in them but this map picker makes the client objects break can anyone help thankyou. because of the heavy requirements to be able to make posts i have to reply to get help its really annoying.

1 Like