• 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  英文好的同学可以直接看原文 。另外,这个原文题目有些让人疑惑,所以我的译文标题做了一些更改。

  • 相关阅读:
    一种client同步server数据的方案
    nodejs package.json解释
    node.js JS对象和JSON字符串之间的转换
    setInterval的用法
    ActiveMQ 入门Nodejs版
    ActiveMQ + NodeJS + Stomp 极简入门
    为什么 ++[[]][+[]]+[+[]] = 10?
    Child Process模块
    phantomjs 解码url
    PhantomJSのメモいろいろ
  • 原文地址:https://www.cnblogs.com/tangzhenqiang/p/8891712.html
Copyright © 2020-2023  润新知