Well is there a way for me to set that chances of ores spawning? LIke a percentage, and have the percentages increase/decrease based on the players depth
You can make a table with items based on their chance. Example:
local chanceTable = {"ruby", "ruby", "ruby", "diamond"}
So use math.random to get a random component in the table. Here, the chance of getting “ruby” is 75%, and “diamond” 25%.
What happens if I wanted an ore to be like 1/5000? I’d have to have 4999 other options
Hi. Are you sure you used math.randomseed
in this script or another one? This could be making the script return similar results everytime.
Also math.random(1, 5000) == 1
could represent a chance in 5000 of returning the desired value. In fact that’s not true (math.random returns a pseudo-random number), but this doesn’t mean you can’t use this method to set specific chances. Statistically, the real chance will be similar to 1/5000 using different seeds.
Well cause if I did
if math.random(1, 10) == 1 then do
print('Copper')
elseif math.random(1, 25) == 1 then do
print('Silver')
elseif math.random(1, 50) == 1 then do
print('Ruby')
elseif math.random(1, 5000) == 1 then do
print('Fire Crystal')
end
That’s not technically a 1 in 5000 shot. As it would have to get through the other random above it first, before the 1 in 5000
Well, I’ve always worked with probabilities and math.random using this method (not necessarily the best, but that’s all I needed; maybe a more experienced user can help you):
local RandomNumber = math.random(1, 5000)
if RandomNumber <= 500 then --10%
print('Copper')
elseif RandomNumber > 500 and RandomNumber <= 700 then --4%
print('Silver')
elseif RandomNumber > 700 and RandomNumber <= 800 then --2%
print('Ruby')
elseif RandomNumber == 5000 then --0.02%
print('Fire Crystal')
end
Note that this wouldn’t work in case the sum of probabilities is bigger than 1.
This is a very inefficient way of programming this which mishajones made clear in his post. Every time you want to add a small item to be generated you have to calculate the math and add another elseif
Instead…
The reason math.random is yielding results that seem non random is because that’s what the method does. Math.Random is a pseudo-random generator. This means there’s an underlying seed that causes the results to created in a “random” pattern.
The weight table is by far the best option in this situation. It’s easy to add and remove options, and it’s fairly easy to understand and manipulate.
https://devforum.roblox.com/t/random-blocks-not-being-random/425000/6?u=mrasync
Using the weight table tho, I can’t see a simplified way to edit the values based on a players depth (increasing and decreasing odds of ore spawns)
I wonder if you should try using Random.new() with a seed and then try out nextInteger. That might yield very good results.
Secondly, what does the GetChance function do? I can’t find it in the provided code.
What I would personally do is use a weight table, “convert” it into an array, and use that as a randomizer. I can’t guarantee efficiency though.
local chances = {
Gold = 20; -- 20/5000
Silver = 60; -- 60/5000
Bronze = 4919; -- 4919/5000
Diamond = 1; -- 1/5000
}
local new_chances = {}
function updateChances()
new_chances = {}
for i, v in pairs(chances) do
for a = 1, v do
new_chances[#new_chances+1] = i
end
end
end
updateChances()
math.randomseed(os.time())
print(new_chances[math.random(1, #new_chances)])
-- lets say i want to set new weight factors
chances.Gold = 99
chances.Silver = 1
chances.Bronze = 0
updateChances()
print(new_chances[math.random(1, #new_chances)])
Simple have a table like this
local thingsToSpawn = {
Gold = 20;
Silver = 60;
Bronze = 4919;
Diamond = 1;
}
This will allow you to easily add a remove values.
But what if I wanted to have specific depths value etc?
Like a minimum depth for spawning and max depth for spawning? Setting different values for each layer, etc.
local chances = {
Gold = 20; -- 20/5000
Silver = 60; -- 60/5000
Bronze = 4919; -- 4919/5000
Diamond = 1; -- 1/5000
}
local new_chances = {}
function updateChances()
new_chances = {}
for i, v in pairs(chances) do
for a = 1, #v do -- ERROR HERE
new_chances[#new_chances+1] = i
end
end
end
local function GetBlock(position)
updateChances()
math.randomseed(os.time())
print(new_chances[math.random(1, #new_chances)])
end
Subtables would be you answer. You would have to edit your algorithm to pick but you can do something like this,
local thingsToSpawn = {
Bronze = {
maxChance = 100,
minChance = 80
},
Silver = {
maxChance = 70,
minChance = 50
},
Gold = {
maxChance = 40,
minChance = 20
},
Diamond = {
maxChance = 10,
minChance = 1
}
}
For different layers you would have different tables, or if you are OK with having large tables you could have one large table. You could do something like this.
local thingsToSpawn = {
ThisLayer = {
Bronze = {
maxChance = 100,
minChance = 80
},
Silver = {
maxChance = 70,
minChance = 50
},
Gold = {
maxChance = 40,
minChance = 20
},
Diamond = {
maxChance = 10,
minChance = 1
}
},
ThatLayer = {
Bronze = {
maxChance = 100,
minChance = 80
},
Silver = {
maxChance = 70,
minChance = 50
},
Gold = {
maxChance = 40,
minChance = 20
},
Diamond = {
maxChance = 10,
minChance = 1
}
}
}
I have mine create an array with all the choices. Then If I have just chosen and entry, I remove it from the array.
You can have it add more entries of a certain type the less it’s chosen, giving it more of a chance to be picked.
You also should change your random seed based on the os.time() if the choices are the same every game.
But really it’s a hat of names. If a name is picked, it’s removed from the hat. If one isn’t picked enough, I add more bits of paper with that name on it.
If I want to be strict, I can just tell it how many times to add each name. So maybe out of 100 or so entries, 20 are Gold, 30 are Silver, and 50 are copper. etc. But you can reduce the work by reducing the numbers and keeping the same chance. Eg, 2, 3, and 5 is the same chance as 20, 30, 50.
If it is crazy amounts 5000+ entries, you could just use a check.
If a drop, then is it a good drop? Value 1 in 5.
If it’s a good drop, is it a really good drop? 1 in 5.
If it’s a really good drop, is it a super good drop? 1 in 5.
If it’s a super good drop, is it an epic drop? 1 in 5.
Same principle though. 4 of the 5 entries are “NormalDrop” the 5th is, “GoodDrop”
If it equals “GoodDrop”, etc.
Or if you are just putting out blocks everywhere, just dump 4000 of bronze at random positions, then dump 300 copper, then 100 silver, then 20 gold.
My blocks are procedurally generated
Not sure where the idea of inefficiency of having many items in a table came from but I’ve heard it before. It’s no more efficient that any other way of doing storing many objects.
There’s no need to have 10 duplicate values? Why would you ever need to do that? I was just posing an example without an regards to actual efficiency between the lines. The only other easy way to do this efficiently is…
local thingsToSpawn = {
Bronze = {
ThisLayer = {
minChance = 10,
maxChance = 20
},
ThatLayer = {
minChance = 50,
maxChance = 150
}
},
Gold = {
ThisLayer = {
minChance = 10,
maxChance = 20
},
ThatLayer = {
minChance = 50,
maxChance = 150
}
}
}
I’m unsure of any other alternatives to this.
Did I? Their method was vague and I’m not sure where I defended it. Sorry for the confusion
3 choices.
1, You can drop them all at once as square blocks that aren’t visible. Then as someone gets close, it just makes it visible and changes it’s mesh to look complex. Like how buildings in Open world games are just blocks until you get closer.
2, But to me, I think you would be best off just rolling if it’s a Bronze or not. If not, roll if it’s a Copper or not. If not, roll if it’s a Silver or not. If not, roll if it’s a Gold or not.
3, Either that or have 5000+ entries in an array, and get a random value between 1 and array length.
Just test all 3 and see which one you like best. Make a test map. Run each choice and look at your performance and see which is running most efficient.
You just have that for each layer you are on. If surface then. You can just have it as a function. You can even have it as a separate script that’s just required. It just needs to output 1 value. Bronze. Gold. Whatever.