How do I use math.random

Hello everyone, this is a tutorial about math.random in scripts that can be used in many ways. I will show you how you can use math.random with positions. If you think you’re missing something, respond to this topic and others may help you and I might aswell change this topic if people request it.

  • Info before we start:

math.random is always a number, if its not it will call out an error. An example of a good script with math.random:

local robux = 1 -- variables
local tix = 16
local buildersclub = 500
local egg = 80

local variables = {robux, tix, buildersclub, egg}
local chosenVariable = variables[math.random(1, #variables)] -- This will pick one of the 4 items in the table

print(chosenVariable) -- This will print out one of the items we have putten in the variable table

link to roblox resources:

math | Roblox Creator Documentation
Random | Roblox Creator Documentation

local raindrops = 0 -- amount of parts dropped, I will come back about this later in the script

local function rainFunc() -- making a function called rainFunc that we can use late in the script
	local x = math.random(-20,40) -- You can’t say (40, -20) since 40 is not greater than -20.
	local y = 20 -- If you want the Y-axis to be higher, do something like: math.random(20,30), which will pick a number between 20 and 30
	local z = math.random(-20,40)
	
	local raindrop = Instance.new('Part') -- Inserting a part
	raindrop.Name = 'raindrop' -- Naming the part
	
	raindrop.BrickColor = BrickColor.new('Pastel Blue') -- These are all the properties of the part
	raindrop.Size = Vector3.new(0.5,1,0.5)
	raindrop.Parent = workspace
	raindrop.Position = Vector3.new(x,y,z)
	raindrop.Anchored = false
	
	raindrops = raindrops + 1 -- As we saw earlier in the script: Local raindrops = 0, so every time this function is called, that variable will update
end


while task.wait() do -- This is the script that keeps looping around
	if raindrops <= 250 then -- Basically, if local raindrops = less than 250, then we call the function
		rainFunc()
	elseif raindrops >= 250 then -- If local raindrops = more than 250, then we go further to the pairs which is an iterater function 
		for i,v in pairs(game.Workspace:GetChildren()) do -- game.Workspace:GetChildren is basically just getting the children from the Workspace which we can use later on in the game
			wait(0.1) --  it will loop through this in pairs loop every 0.1 second
			if v.Name == 'raindrop' then -- We are now going through all the instances in the workspace and look for a v(value) called 'raindrop'
				v:Destroy() -- If the name of the value is 'raindrop' then we destroy that instance
			end
		end
	end
end
  • End product:

Check the script yourself and when you’re finished let me know what you think about this tutorial. Now, for the more advanced ones reading this script. The script is supposed to be as simplified as possible.

8 Likes

math.random(a,b) generates a random number between a and b.
math.random() returns a number between 0 and 1.
That’s really all you need to know.

1 Like

I am not sure if beginner scripters would understand that :smile:

However, it does seem pretty self-explanatory. But he could’ve mentioned how a cannot be greater than b or a < b and b > a,

In this tutorial I did cover that though

I understand what you mean, however there wasnt an explanation, anyways, great tutorial

1 Like

Yeah, very true. I will change that

1 Like

In short: math.random() returns a random number.

local function rollDice(): number
    return math.random(1, 6)
end

print(rollDice())

This script prints a random integer between two numbers (1 and 6).

Why is this helpful?
This can be helpful for choosing random maps, choosing random game modes, etc.

please never user while wait() loops

What would you suggest to do, instead of while wait() do?

i lost zeuxcg’s post about it but i found something alike

1 Like

While wait() do is only bad practice unless there is a value called and I completely agree I should’ve used task.wait(), I will change it right away :sweat_smile:

dont forget math.random(a) generates a num between 1 and a.

To add on to the examples in this tutorial, seeding is a topic not spoken about very much which deals with the core of how the random API’s work. The docs for the math library mention randomseed, but it isn’t very helpful as to what it does or how it can be useful in certain circumstances.

By default, math.random() is seeded with a changing number (probably some form of time) to produce a “more random” output. However, you’ll notice something curious happens if the seed is changed to a constant value:

math.randomseed(5)
print(math.random(1, 20000)) --> 12143
print(math.random(1, 20000)) --> 16682
math.randomseed(5) -- RESETS THE SEQUENCE
print(math.random(1, 20000)) --> 12143
print(math.random(1, 20000)) --> 16682
math.randomseed(6) -- Different seed
print(math.random(1, 20000)) --> 7518
print(math.random(1, 20000)) --> 10450

If a static seed is used, the sequence of numbers will always be the same if the same parameters are used. This can be useful in cases when you want instant feedback of “randomness” on the client without needing to wait for a response from the server. Both the server and client will agree on the random number as long as updates to the current number in the sequence are communicated. Disclaimer: don’t use this for anything that actually matters such as loot boxes or a glass bridge game


Another addition to the topic of random is Random.new() which behaves exactly like math.random() due to both sharing the exact same internal function. The main difference between the two is Random.new() is more extendable as it also has methods to handle decimal numbers as well as Vector3’s:

print(Random.new():NextNumber(100, 200)) --> number between 100 and 200 with random decimals
print(Random.new():NextUnitVector()) --> returns a random unit vector between -1 and 1 for each axis
--This is handy if you need to randomly choose a vector within a certain "cubed radius":
print(Random.new():NextUnitVector() * 5) --> each axis is between -5 and 5

Notice the wordage of Next; it is implying the returned number is the next number in that sequence. Additionally, Random.new():NextUnitVector() can be used for UDim2’s if the depth is ignored and negative numbers are accounted for:

local randomUnitVector = Random.new():NextUnitVector()
print(UDim2.new(math.abs(randomUnitVector.X), 0, math.abs(randomUnitVector.Y), 0))

math.abs() simply returns the absolute value of the number (turns the number positive if it’s negative); a necessity since :NextUnitVector() can return negative numbers. Here is another way to create a random UDim2 that some may prefer over the above code:

print(UDim2.new(Random.new():NextNumber(), 0, Random.new():NextNumber(), 0))
Benchmark of the two if curious:
--math.abs version --> 0.000000207 each iteration
--calling Random.new() twice --> 0.000000267 each iteration

The differences are negligible so choose whichever you’re more comfortable with.
The benchmark code:

local randomUnitVector, newUDim2

local timer = os.clock()
for i = 1, 100000 do
	randomUnitVector = Random.new():NextUnitVector()
	newUDim2 = UDim2.new(math.abs(randomUnitVector.X), 0, math.abs(randomUnitVector.Y), 0)
end
print(os.clock() - timer)
task.wait(1)

timer = os.clock()
for i = 1, 100000 do
	newUDim2 = UDim2.new(Random.new():NextNumber(), 0, Random.new():NextNumber(), 0)
end
print(os.clock() - timer)

Lastly, let’s say you don’t want to use the same seed every time and wish to reduce predictability; at the same time, you want instant random feedback on the client (like mentioned earlier). Luckily, :Clone() can be used on a random object to get the current state of a “random” sequence of numbers. Here’s an example of it in action:

local sequence = Random.new() -- No static seed (different numbers every time this runs)
print(sequence:NextInteger(1, 20000)) --> 7609
local clonedSequence = sequence:Clone() -- clone its current state
print(sequence:NextInteger(1, 20000)) --> 14510
print(sequence:NextInteger(1, 20000)) --> 1198

print("--------------------------")
print(clonedSequence:NextInteger(1, 20000)) --> 14510
print(clonedSequence:NextInteger(1, 20000)) --> 1198
1 Like