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


前言

當我最初寫游戲時,我經常使用標准Random()函數,然后寫一堆if和else條件來我獲得預期結果。如果結果不太好,我會寫更多的條件進行過濾或者篩選,直到我覺得游戲變得有趣。最近我發現有更好的方法。內置的Random類並沒有問題,問題是使用內置的Random類很難達到我們的預期效果。

現實生活中,以拋硬幣為例,時而會拋出連續多次花或者字。那么如果在游戲中,可能表現為多次連續的暴擊或是硬直,盡管有時暴擊和硬直的概率很低,但依舊有可能連續出現,讓人感覺詭異。那么為了解決類似的問題,前輩們想了很多種方法,比如說特殊值過濾等等。我們今天介紹的是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  英文好的同學可以直接看原文 。另外,這個原文題目有些讓人疑惑,所以我的譯文標題做了一些更改。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM