● Hey! So basically, I’m making a game where it will choose random obby maps and you will have you reach the end to win. So far, the game is finished and everything works perfectly fine EXCEPT that the game sometimes chooses the same previous map, or it doesn’t choose a specific map at all throughout the entire playtime. This is kind of annoying because when my friends play it, they often get bored of playing the same map over and over again, sometimes It even chooses 5 same maps in a row even though there are 8 maps already.
● I believe It’s the math.random. Well, they say It is completely random but I don’t think it is that random. I’ve tried looking for solutions for 2 days and none of the topics that I’ve found seem to be related to this. So is there happen to be a way to modify the code lines a bit so that they will feel more random? Or to make it choose all the maps once by once without repeating the same map and then when it chooses the last map it redos the whole progress again?
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
Maps = ServerStorage:WaitForChild('Maps'):GetChildren()
Text = ReplicatedStorage:WaitForChild('IntermissionText')
while true do
local Countdown = 15
repeat wait(1)
Countdown = Countdown - 1
Text.Value = 'Intermission : '..Countdown
until Countdown <= 0
Text.Value = 'Selecting Map'
local ChosenMap = Maps[math.random(1, #Maps)]:Clone()
local MapTeleport = ChosenMap.SpawnLocation
Store the previous map in a variable, then check if map.random selects the previous and if it does pick another again. Once it picks a new map set the previous variable to the new map.
What I do with random selection for my game is have a “Reference” table, which is all the items you want to randomize, and then create a second table to basically read from the reference table and then be used for actually picking the random values.
local referenceTable = {
"String",
"Hello",
"Cool"
}
local valuesToChoose = {}
After that, you want to basically:
Clone every item into the second (empty) table (so it looks identical)
Before choosing a value, check to make sure the second (to choose from) table isn’t empty. If it is empty, reload it from the reference table
Then, choose your random value, and then delete it from the second (choosing) table
I use this because it seems to be the easiest way to visualize what hasn’t been chosen, and it’s pretty easy to implement.
Pick 2 prime numbers. Lets say, 7 and 5. “5” is the number of maps to choose from. If there are only 4? That’s fine, let the 5th be popular vote. Here we go:
Multiples of 7:
7,14,21,28,35,42,49,56,63,70
Multiples of 7, modulus 5:
2,4,1,3,0,2,4,1,3,0
Notice it’s a pattern, looks random, and everything gets selected once. The trick is, you can’t use 7 more than 5 times, or its a pattern. You switch to a different prime. The second prime will always cycle through the first prime without repeats.
This is an example of how to not get the same random result twice in a row. My method proves to work in practically anything - Map selecting, random players, music pickers, etc.
You can implement the code below into yours. It’s a pretty simple concept
local stages = somewhere:GetChildren()
local currentMap = nil
local previousMap = nil
repeat
currentMap = stages[math.random(1,# stages)]
wait()
until currentMap ~= previousMap
previousMap = currentMap
For some weird reason, my random generator picks the same number many times in a row and it caused a big performance decrease. Even though the chances are really rare that you can get the same exact map infinitely, you still don’t want to loop to go on for a long time.
This is something I made, where it has more than one random generating but it will never cause a performance drop like repeat which is possible.
(It’s kind of written ugly with ands and ors. It’s not that complicated, I just decided to make one-line if statements.)
local LastIndex: number?
local function RandomNewElement<T>(array: { [number]: T }, seed: number?): T
local RNG = Random.new(seed)
if LastIndex == nil then
LastIndex = RNG:NextInteger(1, #array)
return array[LastIndex]
end
local firstSelectionIndex = ((LastIndex == 1) and 2 or (RNG:NextInteger(1, LastIndex - 1)))
local secondSelectionIndex = ((LastIndex == #array) and (#array - 1) or (RNG:NextInteger(LastIndex + 1, #array)))
-- Range
local randomSelectionIndex = (
(LastIndex == 1 or LastIndex == #array) and (RNG:NextInteger(firstSelectionIndex, secondSelectionIndex))
or ((RNG:NextInteger(1, 2) == 1) and firstSelectionIndex or secondSelectionIndex)
)
LastIndex = randomSelectionIndex
return array[LastIndex]
end
Since I used this code, there was never a big pause in my game when the map was randomly selected. A new map was always being randomly selected, and the performance was consistent in all of the decisions.
Just to mention, this won’t work if the array is not fixed.