Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

Is it possible to pick something random BESIDES math.random (EXP: string, players, etc..)?

Asked by 9 years ago

I tried doing this, by doing string.random (which assuming is not even close to the answer, or something that even exists), then I wanted to see if string variables would work with math.random, but they didn't.

So how exactly do I do other random stuff besides math.random?

1 answer

Log in to vote
16
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago
Edited 7 years ago

The only random functionality Lua provides is math.random. It does three things:

  • When called with no arguments, returns a real number between 0 and 1 (includes 0, excludes 1)
    • math.random() --> 0.58201314802
  • When called with one argument, returns a whole number between 1 and that number
    • math.random(5) --> 4
  • When called with two arguments, returns a whole number between the two arguments
    • math.random(17, 20) --> 18

Remember that at a fundamental level, everything on the computer is just numbers, so this shouldn't be too discouraging. If we have random numbers, we should be able to get random anything.


Random Point along a Line

Let's say you want a random number x between low and high. Then we can write x as low + m where m is between 0 and high - low.

As a result, we can generate x as

x = low + (high - low) * math.random()

This is uniformly between low and high (including decimal numbers).

You can use the same math to generate points randomly between two Vector3s.

For the types that have a :Lerp method like Color3, Vector3, and CFrame, you can also take advantage of math.random() in a similar way:

x = low:lerp(high, math.random())

Random Things from Lists

For instance, let's say we want to pick a random thing from a list:

flavors = {"chocolate", "vanilla", "strawberry"}

We can only pick random numbers, so what exactly is numbered about this list? There's an obvious thing: the keys. flavors[1] is "chocolate" while flavors[3] is "strawberry".

That means if we can pick a random number of 1, 2, and 3, we can turn that into a random element of flavors.

In general, to choose a random element from list, you can use

randomElement = list[ math.random(#list) ]
-- math.random(#list) is a random index of list... thus
-- the thing at that position-- `list [ __ ]` --is a random element of list

This is the fundamental way that everything is done. Figure it out in terms of numbers!

Random Positions

One way you can get "random positions" is when you're doing something like picking a random spawn location. In that case, you would probably actually use picking a random thing from a list.

Other times, you want to pick a random point in a particular region.

Random Position in Rectangle

A parallelogram (e.g., rectangle) can be defined in terms of a corner and its two sides as vectors.

For instance

start = Vector3.new(0, 20, 0)
right = Vector3.new(10, 0, 0)
up = Vector3.new(0, 30, 0)

-- Axis-Aligned Rectangle from (0, 20, 0) to (0, 20, 0) + (10, 0, 0) + (0, 30, 0) = (10, 50, 0)

we can generate a random point inside pretty easily:

local u = math.random()
local v = math.random()

local point = start + right * u + up * v

Often, these rectangles will be ones parallel to the XZ plane. This makes the above form in a way simpler:

wide = Vector3.new(1, 0, 0) * width -- or Vector3.new(width, 0, 0)
tall = Vector3.new(0, 0, 1) * height -- or Vector3.new(0, 0, height)

local point = start + wide * math.random() + tall * math.random()
-- This would be the same as
local point = start
    + Vector3.new(math.random() * width, 0, 0)
    + Vector3.new(0, 0, math.random() * height)
-- which is the same as
local point = start
    + Vector3.new( math.random() * width, 0, math.random() * height )

Often I see code that looks like this:

pos = Vector3.new( math.random(-50, 200), 0, math.random(-30, 100) )

I would consider this to be wrong, usually, because it will only generate them to the nearest integer. You should use the full range of numbers, like in the above:

pos = Vector3.new( -50 +  math.random() * 250, 0, -30 + math.random() * 130 )

Random Point in Sphere

At first, it would seem that generating a random point inside of a sphere would not be very different.

Here's a simple (bad) solution:

-- returns a random vector in the cube ranging from
-- [-1, 1] for x, y, z
function randomCube()
    return Vector3.new(
        math.random() * 2 - 1,
        math.random() * 2 - 1,
        math.random() * 2 - 1)
end

function randomSphere()
    local cube = randomCube()
    if cube.magnitude > 1 then
        return cube.unit
    else
        return cube
    end
end

The idea is that we just "clamp" the points outside of the unit sphere to the surface. While this will generate random points and they will all be in a sphere, they won't be uniform. Since there's a lot of space outside of the sphere near the corners of the cube, there will be 6 points on this "sphere" that are much more common than the other points.

That would mean if we used the above (or for that matter, simply randomCube) for inaccuracy in a game, you would have a different amount of inaccuracy when firing diagonally as opposed to horizontally.

What's the solution? There aren't overly nice ones. (You can search for them online). A simple (but very slow) option is to just repeat until you get something inside the sphere:

function randomSphere()
    while true do
        local c = randomCube()
        if c.magnitude < 1 then
            return c
        end
    end
end

See also Sphere Point Picking on MathWorld for another way to do it (and also why using polar coordinates isn't a solution)


If there's another specific thing you want to ask about, comment on it and I will write a portion on it.

1
Great thorough explanation! Can you tell me how you make those line separators? DigitalVeer 1473 — 9y
1
The line breaks are made using a string of hypens or underscores I believe. IIRC, five is enough: ----- adark 5487 — 9y
0
Can't you generate a random point inside a sphere easily with polar coordinates? Choose two random angles between 0 and 2pi, representing the angle about 2 of the coordinate axes, then a random magnitude between 0 and the radius of the sphere. duckwit 1404 — 9y
0
@duckwit: You can generate a random point like that, but it won't be uniform (it will be concentrated towards the poles). This article http://mathworld.wolfram.com/SpherePointPicking.html discusses the solution (added the link in the answer) BlueTaslem 18071 — 9y
Ad

Answer this question