Есть список с объектами и вероятностью их спавна. Сума вероятностей спавна объектов должна равняться 1 (какой-то объект да заспавниться). Для облегчения подбора значений вероятности, есть метод ProbabilityReset который изменяет вероятность на указанное значение для указанного объекта из списка. При этом, изменяя значения и других объектов на соответствующий кэф. ProbabilityReset из кода работает без нареканий.
Есть желание сделать так, что-бы это работало и в редакторе Unity. То есть, при смене одного значения, остальные изменялись автоматически. Есть класс, реализующий эту потребность. Проблема в том, что изменяя значение первого элемента списка все работает, но при взаимодействии с любым другим элементом, первый не реагирует.
public RoadComponent[] objectPool; public struct RoadComponent { public GameObject spawnObject; [Range(0f, 1f)] public float probability; } public void ProbabilityReset(int objName, float newProbability) { objectPool[objName].probability = newProbability; float otherProbs = 0; for(int i = 2; i < objectPool.Length; i++) { if(i != objName) { otherProbs += objectPool[i].probability; } } float k = (1 - newProbability) / otherProbs; for (int i = 2; i < objectPool.Length; i++) { if (i != objName) { objectPool[i].probability *= k; } } //ProbabilityCheck(); } #if UNITY_EDITOR using UnityEngine; [ExecuteAlways] public class RG_Editor : MonoBehaviour { public RoadGenerator1 rg; void Update() { for(int i = 2; i < rg.objectPool.Length; i++) { rg.ProbabilityReset(i, rg.objectPool[i].probability); } } } #endif
Например.
В редакторе есть массив с 5 элементами типа RoadComponent. Первые 2 не принимают участия в расчетах.
probability[2]=0.6
probability[3]=0.2
probability[4]=0.2
Если изменить probability[2]=0,8, то 3 и 4 станут равными 0,1
Если изменить probability[3]=0,4, то 2 останется равным 0,6, а 4 будет равным 0
Если изменить probability[4]=0,4, то 2 останется равным 0,6, а 3 будет равным 0
Не могу понять, либо я упускаю лишнюю запятую, либо совершил логическую ошибку.
ProbabilityReset у тебя вызывается для всех индексов по порядку, соответственно какое бы ты значение не поменял в инспекторе, сперва все значения нормализуются при зафиксированном первом.
Тебе нужно знать, какое именно значение поменялось и нормализовывать остальные об него. Для этого надо либо писать нормальный инспектор, либо кэшировать все значения и сравнивать с актуальными
Посмотри метод OnValidate, может пригодиться
meekobold, спасибо за то, что направили на путь истинный. Переделал метод Update() и перенес его в основной скрипт как OnValidate(). Осознал, что в старом скрипте в Update вызывал ProbabilityReset для всех probability, а не только для новой. Кому интересно что я там наваял, вот код OnValidate().
#if UNITY_EDITOR void OnValidate() { int calcFrom = 0; bool loaded = false; if(!loaded) { for (int i = 2; i < objectPool.Length; i++) { oldProbs.Add(objectPool[i].probability); } loaded = true; } for (int i = 2; i < objectPool.Length; i++) { for(int j = 0; j < oldProbs.Count; j++) { if (i - 2 == j && oldProbs[j] != objectPool[i].probability) calcFrom = i; } } if(calcFrom != 0) { ProbabilityReset(calcFrom, objectPool[calcFrom].probability); calcFrom = 0; for (int i = 2; i < objectPool.Length; i++) { for (int j = 0; j < oldProbs.Count; j++) { if (i - 2 == j) { oldProbs[i - 2] = objectPool[i].probability; } } } } } #endif