Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

How to spawn a drop with a probability?

Discussion in 'Scripting' started by SebGM2019, Mar 13, 2020.

  1. SebGM2019

    SebGM2019

    Joined:
    Aug 3, 2018
    Posts:
    34
    I got a custom class called "Drop" (I use Seralizable so that it shows on the Editor):
    Code (CSharp):
    1. [Serializable]
    2. public class Drop
    3. {
    4.     [SerializeField]
    5.     public GameObject dropObject;
    6.     [SerializeField]
    7.     public float dropProbability;
    8.    
    9.     public Drop(GameObject dropObject, float dropProbability)
    10.     {
    11.         this.dropObject = dropObject;
    12.         this.dropProbability = dropProbability;
    13.     }
    14. }
    As you can see, this little class saves a gameObject with its correspondant drop probability.
    In my EnemyScript, I have a public list of drops, so that I can assign them on the editor with all its properties.
    However, this list can be of a variable size, so here's the problem.
    I should be able to put a drop probability of 1-100%, and get a drop corresponding to these probabilities. How could I achieve that?
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Just manually make sure all dropProbability values add up to 1f (100%), and then get a random float between 0f and 1f. Then loop through the list of drops, adding up their dropProbability values, until you meet or exceed the random value (meaning you found your random drop). Then you use that drop.

    Use the last drop in the list if you never meet/exceed the random value in case of some float accuracy issues with the addition which causes that condition to never be met.

    edit: here's a quick example
    Code (csharp):
    1. //Returns a random drop based on the individual drop's dropProbability
    2. //Returns null if the provided list is empty
    3. public static Drop ChooseDrop(List<Drop> listOfDrops)
    4. {
    5.     Drop chosenDrop = null;
    6.  
    7.     float randomChance = Random.Range(0f, 1f);
    8.  
    9.     float probabilityTotal = 0f;
    10.     foreach (Drop d in listOfDrops)
    11.     {
    12.         chosenDrop = d;
    13.         probabilityTotal += d.dropProbability;
    14.         if (probabilityTotal >= randomChance)
    15.         {
    16.             break;
    17.         }
    18.     }
    19.  
    20.     return chosenDrop;
    21. }
     
    Last edited: Mar 13, 2020
  3. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Note that if you want to avoid having to manually make sure all dropProbability values add up to 1f (100%), you could make this a weights system instead of percentages. All you'd have to do is add up all the dropProbabilities in the list, and do a Random.Range between 0f and that total instead of 0f to 1f. Might save a little work. You could still use it as a percentage system, but not be limited to that.

    Code (csharp):
    1. //Returns a random drop based on the individual drop's dropProbability
    2. //Returns null if the provided list is empty
    3. public static Drop ChooseDrop(List<Drop> listOfDrops)
    4. {
    5.     Drop chosenDrop = null;
    6.  
    7.     float probabilityTotal = 0f;  //get a total of all dropProbability values
    8.     foreach (Drop d in listOfDrops)
    9.     {
    10.         probabilityTotal += d.dropProbability;
    11.     }
    12.  
    13.     float randomChance = Random.Range(0f, probabilityTotal);  //get a random float between 0f and the probabilityTotal
    14.  
    15.     probabilityTotal = 0f;  //Now reuse probabilityTotal to track where we are in iterating the list again
    16.     foreach (Drop d in listOfDrops)
    17.     {
    18.         chosenDrop = d;
    19.         probabilityTotal += d.dropProbability;
    20.         if (probabilityTotal >= randomChance)
    21.         {
    22.             break;
    23.         }
    24.     }
    25.  
    26.     return chosenDrop;
    27. }
     
    iodinex64 likes this.
  4. SebGM2019

    SebGM2019

    Joined:
    Aug 3, 2018
    Posts:
    34
    Thanks, it worked perfectly. Just note that if you put the probabilities as integer values, you'll need to divide them by 100:
    probabilityTotal += (d.dropProbability / 100);
    ...
     
    Joe-Censored likes this.