Mathematics in roblox games

Oh… Yeah… Maths, so hated and useful at the same time… Many people are afraid of this when they start programming, because they think they are not capable, that they will not understand it or they are simply lazy to learn, but it is not as difficult as most people think, with this post, I will try:

Math library

Values

math.pi

Returns the number pi (𝛑).

math.huge

Returns infinite.

Approaches

math.floor(x)

This function removes the decimals from a number and leaves only the integer part.

math.floor(5.9746) --> 5
math.floor(543.235) --> 543
math.ceil(x)

This function checks if the number you give it has decimals, if so, it returns the next number, if not, it stays as is.

math.ceil(6) --> 6
math.ceil(6.1) --> 7
math.ceil(6.5) --> 7
math.ceil(6.9) --> 7
math.round(x)

This function rounds the number, looks at the first decimal place and if it is five or more, it gives the next number, if it is less, it removes the decimals.

math.round(5.5) --> 6
math.round(5.3) --> 5
math.round(5.8) --> 6

Random numbers

math.random(min, max)

This function gives a random number between the first and the second, if you only give a number, it will give you a random number between 0 and the number you have specified, but if you do not put any number, it returns a random number between 0 and 1.

math.random(5, 10) --> Any number between 5 and 10
math.random(10) --> Any number between 0 and 10
math.random() --> Any number between 0 and 1
math.randomseed(x)

Random numbers do not really exist, so we use a substitute, pseudo-random numbers. I’m sure you’re wondering how Roblox does it with math.random or any other game, it’s easy, there’s a trick to it.
First you have a formula, for example, 7*seed+3, where seed is any initial number, in this case we will use 2, then the calculation 7*2+3=17 is done, then the 17 is set as seed being the next calculation 7*17+3 and so on, but of course we also have to go back and not just increase, then we put a maximum and see how many times the result of that number passed, so if it is 5, 15 would be removed from the 17, leaving 2 and so on.
So, knowing this, this function establishes the seed of the pseudo-random numbers:

while task.wait(.5) do
      math.randomseed(1)
      print(math.random(10))
end

If you put this code, you will see that, despite being a random number, it is putting the same number, since you are specifying a seed before each math.random, converting it all the time in the same calculations, therefore, same result.

Minimum and maximum

math.min(x, y, ...)

This function accepts any number of numbers to compare them and return only which is the smallest.

math.min(7, 5, 45, 2, 78) --> 2
math.min(567, 464, 251, 875, 753) --> 251
math.max(x, y, ...)

This function accepts any number of numbers to compare them and return only which is the largest.

math.max(7, 5, 45, 2, 78) --> 78
math.max(567, 464, 251, 875, 753) --> 875

Cut out numbers

math.sign(x)

If the number is less than 0, returns -1, if greater, returns 1, and if 0, returns 0.

math.sign(.3) --> 1
math.sign(0) --> 0
math.sign(-.3) --> -1
math.clamp(x, min, max)

This function requires three numbers to be specified, the number, the minimum and maximum. If the number is less than the minimum, it returns the minimum; if it is greater than the maximum, it returns the maximum and if it is between those two numbers, it does not modify it:

math.clamp(5, 3, 7) --> 5
math.clamp(5, 7, 10) --> 7
math.clamp(5, 4, 0) --> 4

Easy calculations

math.abs(x)

Returns the absolute value of the number (i.e. the number in positive).

math.abs(5) --> 5
math.abs(-5) --> 5
math.pow(x, y)

Returns x raised to y (x^y).

math.pow(5, 2) --> 5^2 --> 25
math.sqrt(x)

Returns the square root of the specified number.

math.sqrt(25) --> 5
math.exp(x)

Returns e^x (e is the Euler’s number, exponential of x).

math.exp(5) --> 148.41315910258 

math.fmod(x, y)

Returns the remainder of the division of x/y (can also be calculated with x%y)

math.fmod(10, 3) --> 1 (10%3)
math.fmod(10, 2) --> 0 (10%2)

Logarithms

math.log(x, y)

A logarithm is an infinite curve that never becomes straight, useful for calculating the experience needed to level up.
This function needs a number and a base (the base defines what the curve looks like) and returns the result of the logarithm of base y of x:

math.log(10, 5) --> 1.4306765580734
math.log(10, 10) --> 1
math.log(10, 3) --> 2.0959032742894

Logarithms

math.log10(x)

This function returns the base 10 logarithm of x (it is like putting math.log(x, 10)).

math.log10(10) --> 1 (math.log(10, 10))

Angles

math.rad(x)

A radian is a measure of angle, somewhat like degrees, with the difference that 90º is 𝛑/2 rads, 180º is 𝛑 rads, 270º is 3𝛑/2 rads and 360º is 2𝛑 rads. This is used for rotations with CFrame.
What this function does is to pass an angle in degrees and return it in radians.

math.rad(180) --> 𝛑 (3.1415926535898)
math.deg(x)

This function converts radians to degrees.

math.deg(math.rad(180)) --> 180
math.deg(2𝛑) --> 360

Trigonometry

math.sin(x)

The sine is a trigonometric function which represents the Y position of a series of points that form a circle of radius 1, so it sounds a little complicated, but let’s take a closer look:

This one here is its graph, if you look at the number line below, it is in radians since both the sine, cosine and tangent we will need to give it an angle in radians.
As we can see, the sine, depending on the angle you give it, gives values between 1 and -1.
As you know, a right triangle can be drawn between two points, because the sine of an angle is the size of the opposite leg between the inside of the circle and the corresponding point on the circle according to the angle:

imagen_2021-12-26_172728
math-sine-wave

math.cos(x)

The cosine is the same as the sine but changing the axis, but first, let’s see its graph:

As can be seen, it is quite similar to the breast with the difference that it is slightly moved horizontally.
This, like the sine, represents a leg of the right triangle at the center of the circle and a point on the circle that corresponds to the angle that is given to the cosine, but instead of being the opposite, it calculates the adyascent:


unnamed

The magic of joining sine with cosine

If we put these two functions (sine and cosine) together we can calculate a position on the circle, which we can use to make orbits or calculate directions from an angle. Using this method is simple and easy to attach because, as it goes from -1 to 1, we can not only multiply the position obtained to enlarge the radius of this circle, but also just by adding we can change the center position of the circle:
Circle_cos_sin

math.tan(x)

The tangent is the division between sine and cosine.
It represents the distance from the point it intersects on a tangent line to a point on the horizontal dividing line:
imagen_2021-12-27_091320

But this presents us with a problem, in spite of infinite elongation, if we are at 90º or 180º, the line with the hypotenuse is perfectly parallel with the tangent line, then it will go out to infinity.
Its graph would look like this:

7myV


math.asin(x)

This function is said to be the inverse of the sine function since, instead of obtaining a Y position on the unit circle from an angle, it returns an angle from that Y position. (asin(sin(x)) = x)
Captura de pantalla 2022-01-22 104241

math.acos(x)

This function is said to be the inverse of the cosine function since, instead of obtaining a position X on the unit circle from an angle, it returns an angle from that position in X. (acos(cos(x)) = x)

math.atan(x)

This function is said to be the inverse of the tangent function since, instead of getting a distance, you get an angle from that distance. (atan(tan(x)) = x)

math.atan2(y, x)

Imagine a right triangle drawn from two points:

imagen_2022-01-22_104631

If you notice that the hypotenuse is a segment that connects both points, this tells us that we can obtain the rotation that we must apply to one point to make it look at the other. This is exactly what this function is for! But… we have to pass two numbers, the height and length of the triangle, to obtain it, we simply subtract the positions.

But… Watch out! The result is given in radians, keep that in mind when using it.


math.sinh(x)

This is exactly the same as the sine, but with the difference of being on a circle, it is on a hyperbola:


math.cosh(x)

This is exactly the same as cosine, but with the difference that it is on a circle, it is on a hyperbola:


math.tanh(x)

This is exactly the same as the tangent, but with the difference that it is on a circle, it is on a hyperbola:


Extras

math.noise(x, y, z)

Perlin Noise is a black and white image that has the peculiarity of having white dots on a black background surrounded by gray areas:
descarga
For this function you must put three numbers of which two are optional (if you do not put them, they will be set as 0) which are coordinates to know which point of the image to look at and give a value between 0 and 1 depending on the color it is.
This can be used for a map generation.

math.modf(x)

This function returns the integer and decimal part of the number separately:

math.modf(3.5) --> 3, 0.5
math.ldexp(x, y)

This function makes the formula for you: x * 2 ^ y

math.frexp(x)

This function returns the unknown m and n considering that: x = m*2^n

Some formulas

Quadratic trajectory

Sometimes we need to calculate the position in the plane of a thrown object, such as an arrow, a stone or a bird.

Formula: origin + direction * t + (gravity*t*t)/2

First let’s put this formula into a function and specify everything the formula needs to calculate the position:

local function getPosition(origin, direction, gravity, t)
   return origin + direction * t + (gravity*t*t) * .5
end

Let’s start by specifying the origin, this must be a vector which is the position from where the object is launched.

local origin = workspace:WaitForChild("Origin").Position

The direction must also be a vector that, as the name says, tells where to launch, for this you can use trigonometry or LookVector, RightVector and UpVector.

local direction = workspace:WaitForChild("Origin").CFrame.LookVector * 50 + workspace:WaitForChild("Origin").CFrame.UpVector * 67

Gravity is also a vector that of magnitude is the force of gravity and of course, it has to go downward:

local gravity = Vector3.new(0, -workspace.Gravity, 0)

Finally we need t (time) which tells the point of the trajectory where we are, to obtain it, what we will do is to specify an initial value (0) and constantly we will add deltaTime (time between frame and frame in one second) and if you want to modify the speed just multiply it by a number:

local t = 0
while true do
    t += game:GetService("RunService").Heartbeat:Wait()
end

And it would be just a matter of applying the formula!

local function getPosition(origin, direction, gravity, t)
   return origin + direction * t + (gravity*t*t) * .5
end

local gravity = Vector3.new(0, -workspace.Gravity, 0)

local originPart = workspace:WaitForChild("Origin")
local origin = originPart.Position
local direction = originPart.CFrame.LookVector * 50 + originPart.CFrame.UpVector * 67

local bullet = workspace:WaitForChild("Bullet")

local t = 0
while true do
    bullet.Position = getPosition(origin, direction, gravity, t)
    t += game:GetService("RunService").Heartbeat:Wait() * .5
end

Quadratic trajectory

Here you can download a place with the system already made to test it!
Baseplate.rbxl (32.0 KB)

Converting from Euler to Quaternions

Quickly explained, a quaternion is a four-axis rotation based on complex numbers, which is a calculation of a number with an imaginary number (imaginary numbers are non-existent numbers, such as the square root of -1).
Thinking about quaternions is difficult, but there is a formula that makes it easy to create them:

W = cos(x/2) * cos(y/2) * cos(z/2) - sin(x/2) * sin(y/2) * sin(z/2)
X = cos(y/2) * cos(z/2) * sin(z/2) + cos(x/2) * sin(y/2) * sin(z/2)
Y = cos(x/2) * cos(z/2) * sin(y/2) - cos(y/2) * sin(x/2) * sin(z/2)
Z = cos(z/2) * sin(x/2) * sin(y/2) + cos(x/2) * cos(y/2) * sin(z/2)

local function Axis2QuaAxis(x, y, z)
    x *= .5; y *= .5; z *= .5;

    local ca, sa = math.cos(x), math.sin(x)
    local cb, sb = math.cos(y), math.sin(y)
    local cc, sc = math.cos(z), math.sin(z)

    local Axis = {
        w = ca * cb * cc - sa * sb * sc;
        x = cb * cc * sa + ca * sb * sc;
        y = ca * cc * sb - cb * sa * sc;
        z = cc * sa * sb + ca * cb * sc;
    };

    return Axis
end

To convert this to quaternions, this is done with CFrame.new(x, y, z, qX, qY, qZ, qW).

Number

Scientific notation

Scientific notation is used to abbreviate a number that has too many zeros, such as 1,000,000. This is normally done by raising 10 to the number of zeros but in Roblox you can put it directly.
We must see where the zeros are, that is, if it is 0.000001 or 1,000,000 (if they are in front or behind the point), if it is in front we will use the + symbol and if it is behind the - symbol. Once we know the symbol we only have to put 1e symbol number of zeros, for example:

1e+5 --> 100000
1e-5 --> 0.00001
Hexadecimal

We count in decimal (base 10), if so called because we have ten numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. When we reach 9, we add one to the previous number and start again, 9 ->+10, 11, 12, 13, 14, 15, 16, 17, 18, 19… Counting in hexadecimal is exactly the same, but with the difference of counting with more numbers, which, to avoid creating more symbols, we use letters: 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f. Here it is the same, when we reach f we add one to the next number: f → +10, 11, 12, 13, 14, 14, 15, 16, 17, 18, 19, 1a, 1b, 1c, 1d, 1e, 1f… It is possible to count like this in roblox but we must put 0x in front:

0xa --> 10
0x10 --> 16
0xc4df0a --> 12902154
59 Likes

Im no math expert, but I think math.pi is for trigonometry?

1 Like

It would be really useful if you make a tutorial on strings like that. :slight_smile:

Hey! I am currently working on a data compression algorithm, so how do I find out how many decimal places a number has?

like:
41.412 → 3
68.9 → 1
94.4213123 → 5

I tried #tostring(n-math.floor(n)) but it would return something like 0.09999999999999964 instead of 0.1, so the result wasn’t 1, but was instead 37.

Nevermind, I did some more experiments and found a solution:

Incase for any of you who got the same problem, just do this:

#tostring(a)-#tostring(math.floor(a))-1

of course replace a with your variable or number.

I like maths , its good ,not bad

It is the product of dividing the circumference of a circle by its diameter and is useful for calculating the circumference of circles

That’s trigonometry, I use pi to make circles

1 Like