Shuffle Bags讓你的隨機不那麼隨機

前言

當我最初寫遊戲時,我常常使用標準Random()函數,而後寫一堆if和else條件來我得到預期結果。若是結果不太好,我會寫更多的條件進行過濾或者篩選,直到我以爲遊戲變得有趣。最近我發現有更好的方法。內置的Random類並無問題,問題是使用內置的Random類很難達到咱們的預期效果。dom

現實生活中,以拋硬幣爲例,時而會拋出連續屢次花或者字。那麼若是在遊戲中,可能表現爲屢次連續的暴擊或是硬直,儘管有時暴擊和硬直的機率很低,但依舊有可能連續出現,讓人感受詭異。那麼爲了解決相似的問題,前輩們想了不少種方法,好比說特殊值過濾等等。咱們今天介紹的是Shuffle Bag技術,可讓你的隨機數不那麼隨機,由你掌控。函數

什麼是Shuffle Bag呢?

Shuffle Bag是一項讓咱們能夠控制隨機數分佈的技術。性能

其主要原理爲:動畫

  • 設計一個特定分佈數值的集合。
  • 把集合中數值轉載至揹包中。
  • 將揹包中數值隨機打亂。
  • 從揹包中以任意順序(從前日後,從後往前都無所謂)一個一個的抽取數值,抽完不放回,直到揹包爲空。
  • 揹包爲空後,將數據放回,並從新打亂,以後循環利用。
不難看出,Shuffle Bag 特性以下:
  1. 不會產生集合以外的數據。
  2. 它仍然具備隨機性,元素出現的順序仍是隨機的。
  3. 非重複抽取,若是數據集中某個元素只有一個,至多連續出現兩次。

如何實現Shuffle Bag?

原文使用C#,這裏使用Unity C#和泛型,你們能夠很方便的轉譯爲其餘語言。實現並非先把整個揹包先隨機打亂,而是每次抽取時,才進行一次隨機交換,這樣作能夠分攤性能,不至於在揹包數據較多時,打亂揹包消耗某幀過多性能。
using System.Collections.Generic;

using UnityEngine;

public class ShuffleBag<T> {

    
    private List<T> data;
    private T currentItem;
    private int currentPosition = -1;

    private int Capacity { get { return data.Capacity; } }
    public int Size { get { return data.Count; } }

    public ShuffleBag(int initCapacity)
    {
        data = new List<T>(initCapacity);
    }

    public void Add(T item, int amount)
    {
        for (int i = 0; i < amount; i++)
            data.Add(item);

        currentPosition = Size - 1;
    }

    public T Next()
    {
        if (currentPosition < 1)
        {
            currentPosition = Size - 1;
            currentItem = data[0];

            return currentItem;
        }

        var pos = Random.Range(0,currentPosition);
        currentItem = data[pos];
        data[pos] = data[currentPosition];
        data[currentPosition] = currentItem;
        currentPosition--;

        return currentItem;
    }
}

  

如何使用Shuffle Bag?

在個人項目中,我但願NPC播放受傷動畫的機率爲十分之一,而且我不但願看到他偶爾連續播放受傷動畫屢次,也不想長時間不播放受傷動畫。設計

  ShuffleBag<bool> hurtBag = new ShuffleBag<bool>(10);
  hurtBag.Add(false, 9);
  hurtBag.Add(true, 1);
  //當觸發受傷時,調用如下邏輯  
    if(hurtBag.Next())
    {
      Play();
    }

  

附錄

附上參考的原文連接 Shuffle Bags: Making Random() Feel More Random  英文好的同窗能夠直接看原文 。另外,這個原文題目有些讓人疑惑,因此個人譯文標題作了一些更改。blog

相關文章
相關標籤/搜索