I am creating an RPG where weighted spawns are frequently used. Many classes such as monsters, loot or dungeon generation have a variable in them called spawnChance which is a value 0-100 that determiens the spawn rate.
I have previously been using this style of selection to get a random weighted member from an array
var weights = enemy.Select(e => e.spawnChance);
var index = weights.GetRandomWeightedIndex();
return enemy[index];
Here is the extension
public static int GetRandomWeightedIndex(this IEnumerable<float> weights)
{
int count = weights.Count();
if (weights == null || count == 0)
{
Debug.LogWarning($"Weights are invalid");
return -1;
}
else if (count == 1)
return 0;
float w;
float t = 0;
int i;
for (i = 0; i < count; i++)
{
w = weights.ElementAt(i);
if (float.IsPositiveInfinity(w))
{
return i;
}
else if (w >= 0f && !float.IsNaN(w))
{
t += weights.ElementAt(i); ;
}
}
float r = UnityEngine.Random.value;
float s = 0f;
for (i = 0; i < count; i++)
{
w = weights.ElementAt(i); ;
if (float.IsNaN(w) || w <= 0f) continue;
s += w / t;
if (s >= r) return i;
}
return -1;
}
However, i'd like to reduce this code since the method of selecting all floats via linq and then passing it into the extension and then back is rather tedious and used dozens of times.
I thought of using reflection to find a variable called 'spawnChance' inside a generic class, but since everything is generated at runtime that would be quite slow.
Could I possibly turn spawnChance from a simple float into a class, and then somehow write a linq method that will performantly be able to pull that class value out? Due to the project setup the classes cannot inherit from a spawnChance class. Thoughts? Thanks for your time!
Aucun commentaire:
Enregistrer un commentaire