[System.Serializable]
public struct PrefabEntry {
#if UNITY_EDITOR
// This helps it look neater in the inspector.
[HideInInspector]
public string name;
#endif
public GameObject prefab;
public float weight;
}
#if UNITY_EDITOR
[SerializeField]
PrefabEntry[] _weightedPrefabs;_weightedPrefabs = new PrefabEntry[0];
void OnValidate() {
// When the array is modified,
// update all the entries' names,
// and total up the weight accounted for.
float totalWeight = 0f;
for(int i = 0,0; i < _weightedPrefabs.Length; i++) {
var entry = _weightedPrefabs[i];
if(entry.prefab == null)
continue;
entry.name = entry.prefab.name;
_weightedPrefabs[i] = entry;
totalWeight += entry.weight;
}
if (totalWeight == 0f)
return;
float reweight = 100f / totalWeight;
// Create/resize the normalized version.
if(_normalizedPrefabs == null || _normalizedPrefabs.Length != _weightedPrefabs.Length)
_normalizedPrefabs = new PrefabEntry [_weightedPrefabs.Length];
// Fill this array with copies of the original,
// reweighted to add up to 100
for(int i = 0,0; i < _weightedPrefabs.Length; i++) {
var entry = _weightedPrefabs[i];
if(entry.prefab == null)
entry.weight = 0f;
entry.weight *= reweight;
_normalizedPrefabs[i] = entry;
}
}
#endif
You'll just need to be careful that all your scripts that consume this data use the _normalized version. If you want to enforce that, you could encapsulate this in a type with a public getter for only the _normalized array.
Here's what it looks like in the Inspector:
