财运轮在合一中止时如何选择?

0 c# unity-game-engine

有很多关于普通幸运轮的代码,但我找不到任何关于如何控制轮子停止位置的信息?

我的幸运轮应该是这样工作的:1->5,8->12 有 90% 的几率箭头停在那里,6 有 1% 的几率,其他有 9%。

我需要它在游戏过程中积累和增加,例如:1 转后箭头有 2% 的机会停在 6 而不是 1%。

public List<int> prize;
public List<AnimationCurve> animationCurves;

private bool spinning;    
private float anglePerItem;    
private int randomTime;
private int itemNumber;

BoxCollider2D m_collider;
void Start()
{

    spinning = false;
    anglePerItem = 360/prize.Count;      

}
void Update()
{
    if (Input.GetKeyDown (KeyCode.Space) && !spinning) {

        randomTime = Random.Range (1, 4);
        itemNumber = Random.Range (0, prize.Count);
        float maxAngle = 1080 * randomTime + (itemNumber * anglePerItem);

        StartCoroutine (SpinTheWheel (5 * randomTime, maxAngle));
    }
}
IEnumerator SpinTheWheel (float time, float maxAngle)
{
    spinning = true;

    float timer = 0.0f;        
    float startAngle = transform.eulerAngles.z;        
    maxAngle = maxAngle - startAngle;

    int animationCurveNumber = Random.Range (0, animationCurves.Count);
    Debug.Log ("Animation Curve No. : " + animationCurveNumber);

    while (timer < time) {
    //to calculate rotation
        float angle = maxAngle * animationCurves [animationCurveNumber].Evaluate (timer / time) ;
        transform.eulerAngles = new Vector3 (0.0f, 0.0f, angle + startAngle);
        timer += Time.deltaTime;
        yield return 0;
    }

    transform.eulerAngles = new Vector3 (0.0f, 0.0f, maxAngle + startAngle);
    spinning = false;
        Debug.Log( itemNumber);
    Debug.Log ("Prize: " + prize [itemNumber]);//use prize[itemNumnber] as per requirement
}    
Run Code Online (Sandbox Code Playgroud)

财运轮

der*_*ugo 5

首先:你的百分比没有总结

如果你描述1..58..12一起盖90%则只有10%左股之间67

所以,从你的描述中的每个1234589101112将有一个蹦床网上单人的百分比9%6本来就有1%,既然只剩9%下了,也就7有了9%

我暂时保留它,但您可能希望根据您的需要修复这些权重。


你想要的是一个加权随机,例如

private Dictionary<int, int> weights = new Dictionary<int, int>
{
    // Value | Weight TODO: Make sure these sum up to 100
    {1,        9},
    {2,        9},
    {3,        9},
    {4,        9},
    {5,        9},
    {6,        1},
    {7,        9},
    {8,        9},
    {9,        9},
    {10,       9},
    {11,       9},
    {12,       9}
};

// for storing the weighted options
private readonly List<int> weightedOptions = new List<int>();

private void Start()
{
    // first fill the randomResults accordingly to the given wheights
    foreach (var kvp in weights)
    {
        // add kvp.Key to the list kvp.value times
        for (var i = 0; i < kvp.Value; i++)
        {
            weightedOptions.Add(kvp.Key);
        }
    }
}

public int GetRandomNumber()
{
    // get a random inxed from 0 to 99
    var randomIndex = Random.Range(0, weightedOptions.Count);
    // get the according value
    return weightedOptions[randomIndex];
}
Run Code Online (Sandbox Code Playgroud)

目前还不清楚你想如何实施

1 转后箭头有 2% 的机会停在 12 而不是 1%

您不能在不降低一个或所有其他数字的概率的情况下增加单个数字的概率,因为它们总和为 100%。

所以首先考虑:哪些数字应该增加其(他们的)概率,哪些应该减少?


用你的代码

现在有了你的实际代码,我会修改它并在提到的加权列表之前实施

[Serializable]
public class WeightedValue
{
    public int Value;
    public int Weight;

    public WeightedValue(int value, int weight)
    {
        Value = value;
        Weight = weight;
    }
}

public List<WeightedValue> PricesWithWeights = new List<WeightedValue>
{
    //               Value | Weight TODO: Make sure these sum up to 100
    new WeightedValue(1,        9),
    new WeightedValue(2,        9),
    new WeightedValue(3,        9),
    new WeightedValue(4,        9),
    new WeightedValue(5,        9),
    new WeightedValue(6,        1),
    new WeightedValue(7,        9),
    new WeightedValue(8,        9),
    new WeightedValue(9,        9),
    new WeightedValue(10,       9),
    new WeightedValue(11,       9),
    new WeightedValue(12,       9)
};

// seconds one complete rotation shall take
// adjust in the Inspector
public float SpinDuration = 5;

// you can't assign this directly since you want it weighted
private readonly List<int> _weightedList = new List<int>();

private bool _spinning;
private float _anglePerItem;

private void Start()
{
    _spinning = false;
    _anglePerItem = 360f / PricesWithWeights.Count;

    // first fill the randomResults accordingly to the given wheights
    foreach (var kvp in PricesWithWeights)
    {
        // add kvp.Key to the list kvp.value times
        for (var i = 0; i < kvp.Weight; i++)
        {
            _weightedList.Add(kvp.Value);
        }
    }
}

public int GetRandomNumber()
{
    // get a random inxed from 0 to 99
    var randomIndex = Random.Range(0, _weightedList.Count);
    // get the according value
    return _weightedList[randomIndex];
}

private void Update()
{
    // spinning is less expensive to check so do it first
    if (_spinning || !Input.GetKeyDown(KeyCode.Space)) return;

    // how often should the wheel spin before coming to hold
    // 1 is quite boring so I would say at least 2 -> always at least one full rotation
    var randomTime = Random.Range(2, 6);
    // What you had
    //itemNumber = Random.Range(0, prize.Count); 
    // returns a random index .. not the actual value at this index
    var itemNumber = GetRandomNumber();

    // find the original index of the selected random value
    // and its angle by multiplying by anglePerItem
    var itemIndex = PricesWithWeights.FindIndex(w => w.Value == itemNumber);
    var itemNumberAngle = itemIndex * _anglePerItem;
    var currentAngle = transform.eulerAngles.z;
    // reset/clamp currentAngle to a value 0-360 since itemNumberAngle will be in this range
    while (currentAngle >= 360)
    {
        currentAngle -= 360;
    }
    while (currentAngle < 0)
    {
        currentAngle += 360;
    }

    // Now we can compose the actual total target rotation
    // depends on your setup ofcourse .. For my example below I will use it negative (rotation clockwise) like
    var targetAngle = -(itemNumberAngle + 360f * randomTime);

    Debug.Log($"Will spin {randomTime } times before ending at {itemNumber} with an angle of {itemNumberAngle}", this);
    Debug.Log($"The odds for this were {PricesWithWeights[itemIndex].Weight / 100f:P} !");

    // now pass it all on
    StartCoroutine(SpinTheWheel(currentAngle, targetAngle, randomTime * SpinDuration, itemNumber));
}

// spins the wheel from the given fromAngle until the given toAngle within withinSeconds seconds
// using an eased in and eased out rotation
private IEnumerator SpinTheWheel(float fromAngle, float toAngle, float withinSeconds, int result)
{
    _spinning = true;

    var passedTime = 0f;
    while (passedTime < withinSeconds)
    {
        // here you can use any mathematical curve for easing the animation
        // in this case Smoothstep uses a simple ease-in and ease-out
        // so the rotation starts slow, reaches a maximum in the middle and ends slow
        // you could also e.g. use SmoothDamp to start fast and only end slow
        // and you can stack them to amplify their effect
        var lerpFactor = Mathf.SmoothStep(0, 1, (Mathf.SmoothStep(0, 1, passedTime / withinSeconds)));

        transform.localEulerAngles = new Vector3(0.0f, 0.0f, Mathf.Lerp(fromAngle, toAngle, lerpFactor));
        passedTime += Time.deltaTime;

        yield return null;
    }

    transform.eulerAngles = new Vector3(0.0f, 0.0f, toAngle);
    _spinning = false;

    Debug.Log("Prize: " + result);
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明