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");
}
}
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);
}