Files
Cielonos/Assets/Scripts/MainGame/Items/Utilities/Randomizer.cs
SoulliesOfficial 39b43680a9 爆更
2026-07-18 03:16:20 -04:00

84 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
namespace Cielonos.MainGame.Inventory
{
/// <summary>
/// 提供基于 Luck 和 Curse 的通用随机结果。
/// 返回值始终位于 0 到 1 之间;具体含义由调用者自行映射。
/// </summary>
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;
/// <summary>
/// 获取一个不受属性影响的基础随机值。
/// </summary>
public static float Roll01()
{
return Random.Range(MinimumValue, MaximumValue);
}
/// <summary>
/// 根据 Luck 和 Curse 获取一个表示结果好坏的随机值。
/// 0 表示最坏结果1 表示最好结果;两项属性均为 0 时使用中心为 0.5 的正态分布。
/// </summary>
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;
}
/// <summary>
/// Unity 的 Mathf 未提供 Tanh因此通过指数定义计算双曲正切。
/// </summary>
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);
}
}
}