I'm sooooo glad to see you back! I just wanted to express my gratitude towards you, your videos have been soo informative and educative, they gave me the tools to fulfill my dream of programing my own game. I'll be releasing a demo soon, i hope you'll at least watch it :)
Correction!! The code for get_candidate() at 7:20 was written incorrectly; we should be iterating over the number of struct entries, not the ballot total. See the code below. function get_candidate() { var n = irandom(total-1); var na = variable_struct_get_names(candidates); //We test each string segment, looping however long our names array is for(var i = 0, cursor = 0; i < array_length(na); i++) { var candidate = na[i]; cursor += candidates[$ candidate]; if(n < candidates[$ candidate]) { return candidate; } } }
@@nandbolt Thats my point. It is supposed to use cursor.. Otherwise she would not have put it there in the first place. Its an easy fix as I pointed out..
I actually solved this problem in a slightly different way a while back. I dont know that it was a good solution... but it worked for the small generator i needed.. Each time I need to select a candidate, i have some already in there. Candidate A is in twice, then B once. Then candidate C rolls a die. They have a 50% chance to add themselves to the selectable list. Then D rolls, and has a 10% chance to add themselves to the list. Then, i pick from the list of five max (A, A, B, C, D) or three min (A, A, B) by choosing at random. More math is needed this way to tell what the chance to select D is for real, but it worked. 😂
Pew pew pew! She's back in action for 2022! 🥳 Also... choose("Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Cake")
Great video FriendlyCosmonaut, loving the new intro :) you were a big part of the reason I began programming, with all your great videos on GMS2. Thanks for everything!
Great video. I was looking for someone doing an educational video on weighted random choice in gamedev. I might give my own prospective and use the roulette wheel selection algorithm.
I don't quite understand how the Ballot solution solves the problem of having to recalculate the odds of all the other creatures/rocks when you want to add a new one. Would you still not have to calculate the percentage using the total number of rocks in the bag? If I want blue rocks to be picked 30% of the time, I would have to take the total number of rocks in the bag to know how many blue to add. And then if I want red to be picked 60% of the time, I would have to add more red because I just added more blue which caused the total number of rocks to go up, right? Am I missing something?
The segmented version can be scaled down and be a double float, expanding its size to nearly enough to account for any possibility (similar to how the dewey decimal system works). You can speed up the search space by making it a binary tree algorithm. Since the items can be listed multiple times in a segment, it doesn't really matter which node it adheres to, and could be seen in multiple places. If you sort the list by size and cap the size at the square root of the total encumbered, then when you add an item/enemy to the list, you just add it to the smallest one....if it becomes bigger than the cap, you make a new split in the tree, and then resort the list. These cost hardly any processing power to do, as sorting 1 node against an already sorted list is arbitrarily easy.....then when you do a search, the branch splits will have a center point value, if it's less, it goes left, otherwise right. Eventually it hits a node and you do as normal segment. This makes the algorithm O(log(n)), rather than O(n), Insertion is O(1). Subtracting an item/monster from it would be more costly, but usually you would just have a new list already created (this can be done ahead of the area you are entering as a background thread, or be stored in permanence and just loaded in as needed).
A common problem regarding this I personally run into is that once I do change the weights later on, it's hard to really tell by how much I have shifted the other chances. Say I have a bag of 30 green balls, 20 blue, 15 red, and 5 yellow. If I add 13 pink ones, how much rarer have I made the rest?
Hi Cosmonaut. In the second topic, it looks like you are assigning to the cursor but are not using the value anywhere. Am I missing something or is this a typo. 😁
Any chance for new Game Maker tutorials? I've tried to implement Shaun Spalding save and load system and basically it works, but no idea how to save plants from your Farming RPG series 😅 I mean, I can save and load plants and their positions, however saving growth stage is some kind of black magic that I don't know.
"I can save and load plants and their positions" Those are just instances and variables, as is the growth stage. How can you do one but not the other? Edit: Didn't realize this was already a year old. Probably fixed your issue by now.
What about something like this for the blue moon scenario (1% to 40% cake modifier) you generate a number between 1-100, less than 41 it's a cake, greater than 40 belongs to the unmodified percentages so you generate a new number from 1-100 but this time the weights are from this distribution (taurcen =19.1919%, rasp=30.3030%, bunder=50.5050%) that we get by dividing the original (taurcen=19%, rasp=30%, bunder=50%) percentages between 99% ( 100% - (cake=1%) ).
That works for that very specific scenario, but isn't practically a very flexible solution. Let's say you want to add a second variable to the equation (like, for example, current player level, in which Weenies want to be more likely the lower the level). Now, there's not a great way to decide who gets to be the dominant decider. Does Cake get his flat 40% because we're on the blue planet, or does Weenie get his special percent first because of the level. IMO in a practical application, you'll have enough deciding variables to use a simple solution like you suggest.
Therapist: Bunder Isn't Real, It Can't Hurt You.
FriendlyCosmonaut:
Super glad you mentioned the effects of blue moons on Cakes - It's often overlooked when people adopt them
I'm sooooo glad to see you back! I just wanted to express my gratitude towards you, your videos have been soo informative and educative, they gave me the tools to fulfill my dream of programing my own game. I'll be releasing a demo soon, i hope you'll at least watch it :)
Nice, just recently picking this hobby back up after years away from it and this was exactly what I was looking for
Hope to see new videos from you, my friend! :)
Correction!! The code for get_candidate() at 7:20 was written incorrectly; we should be iterating over the number of struct entries, not the ballot total. See the code below.
function get_candidate() {
var n = irandom(total-1);
var na = variable_struct_get_names(candidates);
//We test each string segment, looping however long our names array is
for(var i = 0, cursor = 0; i < array_length(na); i++) {
var candidate = na[i];
cursor += candidates[$ candidate];
if(n < candidates[$ candidate]) {
return candidate;
}
}
}
Should it be? if(n < cursor) { return candidate;}
@@vapidvim I think it is supposed to be that, since the code never actually uses cursor.
@@nandbolt Thats my point. It is supposed to use cursor.. Otherwise she would not have put it there in the first place. Its an easy fix as I pointed out..
@@vapidvim I confirm. It should be:
if (n < cursor) { return candidate; }
I actually solved this problem in a slightly different way a while back. I dont know that it was a good solution... but it worked for the small generator i needed.. Each time I need to select a candidate, i have some already in there. Candidate A is in twice, then B once. Then candidate C rolls a die. They have a 50% chance to add themselves to the selectable list. Then D rolls, and has a 10% chance to add themselves to the list. Then, i pick from the list of five max (A, A, B, C, D) or three min (A, A, B) by choosing at random.
More math is needed this way to tell what the chance to select D is for real, but it worked. 😂
You're an amazing teacher. Please keep making videos if you're able to, they've helped so much!
Pew pew pew! She's back in action for 2022! 🥳 Also...
choose("Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Rasp","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Taurcen","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Gunder","Cake")
Great video FriendlyCosmonaut, loving the new intro :) you were a big part of the reason I began programming, with all your great videos on GMS2. Thanks for everything!
Good to see you back
Woke at 5 am, too early to get going but too late to sleep so I watch useful things, little tear in in my eye rn, so glad to see a new video from you!
seeing this in my recommended made me so happy. your videos always inspire me and educate me :)
Woo! It's been a while, fantastic to see you back! :)
Thank you so much for this video. I've struggled with a satisfactory solution for doing weighted chance for a while now.
Great video. I was looking for someone doing an educational video on weighted random choice in gamedev. I might give my own prospective and use the roulette wheel selection algorithm.
love to see you back
Glad your back!
I don't quite understand how the Ballot solution solves the problem of having to recalculate the odds of all the other creatures/rocks when you want to add a new one. Would you still not have to calculate the percentage using the total number of rocks in the bag? If I want blue rocks to be picked 30% of the time, I would have to take the total number of rocks in the bag to know how many blue to add. And then if I want red to be picked 60% of the time, I would have to add more red because I just added more blue which caused the total number of rocks to go up, right? Am I missing something?
Thank you so much! This really helped me with figuring out how to modify chance for my game's item drop system.
I'm not even a game dev and watch your videos because of your voice and you
You uploaded something! That's amazing! Your channel has been incredibly valuable to me. I hope you're well :)
HOLY IWSEAIGHQWIPGHW!!!!! IT IS YOU! ONE OF MY FAVORITE DEVS!
The segmented version can be scaled down and be a double float, expanding its size to nearly enough to account for any possibility (similar to how the dewey decimal system works).
You can speed up the search space by making it a binary tree algorithm. Since the items can be listed multiple times in a segment, it doesn't really matter which node it adheres to, and could be seen in multiple places. If you sort the list by size and cap the size at the square root of the total encumbered, then when you add an item/enemy to the list, you just add it to the smallest one....if it becomes bigger than the cap, you make a new split in the tree, and then resort the list. These cost hardly any processing power to do, as sorting 1 node against an already sorted list is arbitrarily easy.....then when you do a search, the branch splits will have a center point value, if it's less, it goes left, otherwise right. Eventually it hits a node and you do as normal segment. This makes the algorithm O(log(n)), rather than O(n), Insertion is O(1). Subtracting an item/monster from it would be more costly, but usually you would just have a new list already created (this can be done ahead of the area you are entering as a background thread, or be stored in permanence and just loaded in as needed).
For the candidates with percentages
How cool are bunders tho - they keep your house free of bugs AND de-weed your garden, what a marvel of evolution 💗
this was exactly what i was looking for, thank you so much
Per usual, super easy to understand video. Can't wait for more:)
Legendary coming back! Nice to see you again
You're back! Yay! Hope you're well. You are the best!
This was very useful and I will be trying to implement it in my next GDevelop game project. Thanks!
This is so helpful! And you really do a great job explaining.
(Just sayin’ your tutorials are 💣)
A common problem regarding this I personally run into is that once I do change the weights later on, it's hard to really tell by how much I have shifted the other chances.
Say I have a bag of 30 green balls, 20 blue, 15 red, and 5 yellow. If I add 13 pink ones, how much rarer have I made the rest?
Hi Cosmonaut. In the second topic, it looks like you are assigning to the cursor but are not using the value anywhere. Am I missing something or is this a typo. 😁
hey! hope you'll answer me
do you know how to save object position regarding the screen (camera) without draw gui?
good explanation! :)
Nice video!
Any chance for new Game Maker tutorials?
I've tried to implement Shaun Spalding save and load system and basically it works, but no idea how to save plants from your Farming RPG series 😅
I mean, I can save and load plants and their positions, however saving growth stage is some kind of black magic that I don't know.
"I can save and load plants and their positions"
Those are just instances and variables, as is the growth stage. How can you do one but not the other?
Edit: Didn't realize this was already a year old. Probably fixed your issue by now.
@@razmatazz9310 yeah I fixed it by getting rid of plants at all ;)
@@Kuzyn lol
What about something like this for the blue moon scenario (1% to 40% cake modifier) you generate a number between 1-100, less than 41 it's a cake, greater than 40 belongs to the unmodified percentages so you generate a new number from 1-100 but this time the weights are from this distribution (taurcen =19.1919%, rasp=30.3030%, bunder=50.5050%) that we get by dividing the original (taurcen=19%, rasp=30%, bunder=50%) percentages between 99% ( 100% - (cake=1%) ).
That works for that very specific scenario, but isn't practically a very flexible solution. Let's say you want to add a second variable to the equation (like, for example, current player level, in which Weenies want to be more likely the lower the level). Now, there's not a great way to decide who gets to be the dominant decider. Does Cake get his flat 40% because we're on the blue planet, or does Weenie get his special percent first because of the level. IMO in a practical application, you'll have enough deciding variables to use a simple solution like you suggest.
*thx))*
Mwah
thanks for all ur helpful tutorials :) just a recommendation but id love to see a rhythm game tutorial for gamemaker!
:)
my main takeaway from this video is that you draw 9's so uniquely it blew my mind @1:13