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

相关文章
相关标签/搜索