using System.Collections.Generic;
using UnityEngine;
namespace DanroJump.Gameplay
{
///
/// Один prefab-вариант с весом для случайного выбора.
///
[System.Serializable]
public sealed class WeightedPrefabOption
{
[SerializeField] private GameObject prefab;
[SerializeField] [Min(0f)] private float weight = 1f;
///
/// Prefab, который может быть выбран генератором.
///
public GameObject Prefab => prefab;
///
/// Относительный вес prefab в случайном выборе.
///
public float Weight => weight;
///
/// Выбирает prefab из списка пропорционально весам.
///
/// True, если найден валидный prefab с положительным весом.
public static bool TrySelect(IReadOnlyList options, System.Random random, out GameObject prefab)
{
return TrySelect(options, random, null, out prefab);
}
///
/// Выбирает prefab среди вариантов, которые проходят дополнительный фильтр.
///
public static bool TrySelect(
IReadOnlyList options,
System.Random random,
System.Predicate prefabFilter,
out GameObject prefab)
{
prefab = null;
var totalWeight = 0f;
if (options == null)
{
return false;
}
foreach (var option in options)
{
if (IsSelectable(option, prefabFilter))
{
totalWeight += option.Weight;
}
}
if (totalWeight <= 0f)
{
return false;
}
var roll = (float)((random != null ? random.NextDouble() : 0d) * totalWeight);
foreach (var option in options)
{
if (!IsSelectable(option, prefabFilter))
{
continue;
}
roll -= option.Weight;
if (roll <= 0f)
{
prefab = option.Prefab;
return true;
}
}
return false;
}
private static bool IsSelectable(WeightedPrefabOption option, System.Predicate prefabFilter)
{
return option?.Prefab != null &&
option.Weight > 0f &&
(prefabFilter == null || prefabFilter(option.Prefab));
}
}
}