using UnityEngine; namespace Cielonos.MainGame.Inventory { /// /// 提供基于 Luck 和 Curse 的通用随机结果。 /// 返回值始终位于 0 到 1 之间;具体含义由调用者自行映射。 /// public static class Randomizer { private const float MinimumValue = 0f; private const float MaximumValue = 1f; private const float BiasScale = 0.5f; private const float GoodChanceRange = 0.45f; private const float RegularStandardDeviation = 0.165f; private const float ExtremeStandardDeviation = 0.06f; private const float ExtremeGoodMean = 0.9f; private const float ExtremeBadMean = 0.1f; private const int MaximumNormalRollAttempts = 4; /// /// 获取一个不受属性影响的基础随机值。 /// public static float Roll01() { return Random.Range(MinimumValue, MaximumValue); } /// /// 根据 Luck 和 Curse 获取一个表示结果好坏的随机值。 /// 0 表示最坏结果,1 表示最好结果;两项属性均为 0 时使用中心为 0.5 的正态分布。 /// public static float RollLuckCurse01(float luck, float curse) { GetDistributionParameters(luck, curse, out float bias, out float goodChance, out float extremeWeight); if (Random.value < extremeWeight) { float mean = Random.value < goodChance ? ExtremeGoodMean : ExtremeBadMean; return RollTruncatedNormal(mean, ExtremeStandardDeviation); } return RollTruncatedNormal(0.5f + 0.25f * bias, RegularStandardDeviation); } private static void GetDistributionParameters(float luck, float curse, out float bias, out float goodChance, out float extremeWeight) { float normalizedLuck = Mathf.Clamp01(luck / 100f); float normalizedCurse = Mathf.Clamp01(curse / 100f); bias = HyperbolicTangent((normalizedLuck - normalizedCurse) / BiasScale); goodChance = 0.5f + GoodChanceRange * bias; extremeWeight = normalizedLuck * normalizedCurse; } /// /// Unity 的 Mathf 未提供 Tanh,因此通过指数定义计算双曲正切。 /// private static float HyperbolicTangent(float value) { float exponent = Mathf.Exp(2f * value); return (exponent - 1f) / (exponent + 1f); } private static float RollTruncatedNormal(float mean, float standardDeviation) { for (int attempt = 0; attempt < MaximumNormalRollAttempts; attempt++) { float value = mean + RollStandardNormal() * standardDeviation; if (value > MinimumValue && value < MaximumValue) return value; } return Mathf.Clamp(mean + RollStandardNormal() * standardDeviation, MinimumValue, MaximumValue); } private static float RollStandardNormal() { float u1 = Mathf.Max(Random.value, float.Epsilon); float u2 = Random.value; return Mathf.Sqrt(-2f * Mathf.Log(u1)) * Mathf.Cos(2f * Mathf.PI * u2); } } }