Spawn an Object from an Array of Objects with a Probability

Hey Guys!

I have a spawner that will randomly spawn an enemy game object from an array of game objects. It works fine, but I want to continue to build on this by giving each object inside the array its own probability to spawn.

Here my code:

public class EnemySpawn : MonoBehaviour
{
    public float max;
    public GameObject[] enemies;
    public float interval;
    // Start is called before the first frame update
    void Start()
    {
        BeginSpawn();
    }

    // Update is called once per frame
    void Update()
    {
       
    }

    void SpawnEnemies()
    {
        int whichenemy = Random.Range(0, enemies.Length);
       
        //Instantiate(enemies[whichenemy], transform.position, gameObject.transform.rotation);

        float rangX = Random.Range(-max, max);

        Vector3 pos = new Vector3 (rangX, transform.position.y, transform.position.z);

        Instantiate(enemies[whichenemy], pos, this.transform.rotation);
    }

    IEnumerator KeepSpawning()
    {
        yield return new WaitForSeconds(2f);

        while (true)
        {
            SpawnEnemies();

            yield return new WaitForSeconds(interval);
        }
    }

    void BeginSpawn()
    {
        StartCoroutine("KeepSpawning");
    }
}

Any tips will be much appreciated

Here’s what I’m using. The idea is to give each element a probability value, then sum up the values of all elements, choose a random value inside that sum and then go through the elements again until you reach the chosen value.

/// <summary>
/// Interface that allows an element to provide its probability.
/// Used by <see cref="RandomWeightedElement"/>.
/// </summary>
public interface ProbableElement
{
    /// <summary>
    /// The probability this element is randomly chosen with from a collection.
    /// </summary>
    /// <remarks>
    /// The probability is relative to the probabilities of the other
    /// elements in the collection, it's value is therefore arbitrary.
    /// An item with probability 0 is never chosen, the behavior with
    /// negative probabilities is undefined.
    /// </remarks>
    float Probability { get; }
}

/// <summary>
/// Choose a random element in a collection, respecting the elements' probability.
/// </summary>
/// <returns>The chosen element or `default(T)` if not element could be chosen
/// (collection was empty or all probabilities 0).</returns>
public static T RandomWeightedElement<T>(this IEnumerable<T> collection) where T : ProbableElement
{
    // Calculate sum probabilities of all elements
    var total = 0f;
    foreach (var el in collection) {
        total += el.Probability;
    }

    // Choose a random value inside the total probability
    var random = UnityEngine.Random.value * total;

    // Go through the elements again, until the chosen value is in the element's probability range
    var current = 0f;
    foreach (var el in collection) {
        if (current <= random && random < current + el.Probability) {
            return el;
        }
        current += el.Probability;
    }

    return default(T);
}
2 Likes