/// <summary> /// Это сосбоб случайного получения предмета сравни настольной игре. /// </summary> /// <param name="counter">Счетчик, куда будет занесён результат.</param> /// <param name="items">Предметы в мешочке с их вероятностями.</param> public static void AddRandomItemViaTabletopWay(ref DistributionCounter counter, IEnumerable <float> items) { // Будем тут хранить те предметы, которые еще не достали из мешочка. var probs = items.Select((value, index) => (index, value)).ToList(); // Сумма вероятностей всех предыдущих попыток. Вначале она равна 0. var totalPreviousProbs = 0; // Можем попытаться достать лишь то количество раз, сколько предметов в мешочке. for (var i = 0; i < counter.Size; i++) { // Бросаем две кости на d10, получам значения от 0 до 99 var roll = Random.Range(0, 100); // Достаём новый предмет из мешочка. var probIndex = Random.Range(0, probs.Count); var prob = probs[probIndex]; probs.Remove(prob); // Если бросок костей меньше, чем вероятность текущей вещи плюс сумма вероятностей всех предыдущих вещей, // то это то, что нам нужно. if (roll <= prob.value + totalPreviousProbs) { counter.AddItem(prob.index); return; } // Если бросок кубика нас не устроил, то переходим к следующему totalPreviousProbs += (int)prob.value; } }
/// <summary> /// Это обычный способ распределения по весам. Обратите внимание, какой он простой и не требует такого /// количества вычислений. Random.value вызывается всего один раз вызывается, нет никаких LINQ и все такое. /// </summary> /// <param name="counter">Счетчик, куда будет занесён результат.</param> /// <param name="weights">Реестр предметов с их весами.</param> /// <param name="totalWeight">Сумма всех весов, чтобы не считать каждый раз.</param> public static void AddRandomItemViaWeightWay(ref DistributionCounter counter, float[] weights, float totalWeight) { // Делаем бросок кости и умножаем его на общую массу. var roll = Random.value * totalWeight; // Перебираем все предметы по очереди. for (var i = 0; i < counter.Size; i++) { // Если бросок кубика меньше веса предмета, то добавляем его в счетчик и выходим. if (roll < weights[i]) { counter.AddItem(i); return; } // Перед тем как перейти к следующему предмету, уменьшаем значение значение броска кубика. roll -= weights[i]; } // Добавляем с счечик последний предмет, если ничего не выпало. counter.AddItem(counter.Size - 1); }