随机数几乎应用于游戏开发的方方面面,例如,随机生成的地图,迷宫,怪物属性等,在Unity中,使用随机数非常方便:

         //
// 摘要:
// Return a random integer number between min [inclusive] and max [exclusive] (Read
// Only).
//
// 参数:
// min:
//
// max:
public static int Range(int min, int max);
         //
// 摘要:
// Return a random float number between min [inclusive] and max [inclusive] (Read
// Only).
//
// 参数:
// min:
//
// max:
[FreeFunction]
public static float Range(float min, float max);
         //
// 摘要:
// Returns a random number between 0.0 [inclusive] and 1.0 [inclusive] (Read Only).
public static float value { get; }

正常情况下使用以上三种完全够用了,注意整型的随机是左开右闭的。当然了,你也可以使用System.Random中的方法来随机,可以构造出类似于Unity中的扩展方法:

     static public int Range(this System.Random random, int min, int max)
{
return random.Next(min, max);
} static public float Range(this System.Random random, float min, float max)
{
var r = random.NextDouble();
return (float)(r * (max - min) + min);
}

值得注意的是,System.Random需要实例化才能随机,而UnityEngine.Random是直接使用。

但很多时候,我们除了需要随机数之外,可能会有保留上次随机结果的需求,换句话说,从某一时刻起,我们希望每次都能随机出和上次相同的结果,这个时候就该随机种子出场了。

举例来说,当玩家需要重新进入一次他以前随机出来过的一个迷宫地图进行二次创作,又比如,我们在开发过程中,某个随机单位出现了Bug,但如果下次又没法产生之前随机结果的话,那么就会出现十分头疼的状况了,这样很可能永远有个难以排查的潜在Bug一直在开发过程中而又难以再次复现。

所以,强烈建议,只要是做相对比较复杂的随机行为,我们最好利用随机种子来执行随机

当然了,你说我将所有随机的数据结果序列化保存到本地,那也没问题,但相比随机种子只需要保存一个整型数据来说,哪种方式更可取显而易见。这样也可以大大减少游戏保存的数据容量。

说了这么半天,什么是随机种子呢?

顾名思义,一个种子对应着一个结果,随机种子对应的就是一个唯一的随机结果。

         //
// 摘要:
// Initializes the random number generator state with a seed.
//
// 参数:
// seed:
// Seed used to initialize the random number generator.
[NativeMethod("SetSeed")]
[StaticAccessor("GetScriptingRand()", StaticAccessorType.Dot)]
public static void InitState(int seed);

上面的方法中,参数seed就是传入的随机种子,如果在脚本的一开始执行调用了此方法,那么只有当此次随机种子与上次的种子不相同时,才能随机出不同的随机结果,否则随机的结果总是一样的。

注意,这里指的随机结果是指的所有的随机结果,是一个随机数表,它从本质上改变的是整个UnityEngine.Random类的所有随机方法执行的结果,包括最开始列举的三种中的任意一种。

下面做一个测试就很容易理解了:

 using UnityEngine;

 public class RanTest : MonoBehaviour
{
public bool bDebug;
//System.Random random;
void Start()
{
//random = new System.Random((int)System.DateTime.Now.Ticks);
//string s = "";
//for(int i = 0; i < 233; i++)
//{
// s += random.Range(0, 10) + ",";
//}
//Debug.Log(s); int seed = (int)System.DateTime.Now.Ticks;
if (bDebug)
{
seed = PlayerPrefs.GetInt("Seed");
}
else
{
PlayerPrefs.SetInt("Seed", (int)System.DateTime.Now.Ticks);
}
Random.InitState(seed);
string s = "";
for (int i = ; i < ; i++)
{
s += Random.Range(, ) + ",";
}
Debug.Log(s);
}
}

比如我开了一个Debug模式,如果勾选,则随机种子是从上次保存的数据中读取,随机出来的结果永远是一样的,因为我并没有对保存的数据种子进行任何的更改。

结果如下:

我们发现每次的随机数都一样,因为它们都源于同一个随机种子,无论之后再随机多少次,结果都是这个随机数序列,这个种子对应的结果已经被计算机固定了,除非种子更改,不然随机结果不会变。

当我关闭Debug模式时,正常的随机种子时刻都不会一样,这里用到了System.DateTime.Now.Ticks来保证得到和上次的种子绝不相同的整型,也可以使用guid等。

每次在本地备份一次上一次随机种子的记录,以便随时可以再现上一次随机的结果,只需要轻松勾选Debug即可:

例如,我在第三次时发现了随机产生的其他Bug,这样我只用启动Debug模式反复分析几遍后把复现的隐藏Bug修改结束后再回到正常模式产生新的随机数就好。

另外,我们也可以利用System.Random类的构造方法来实现同样的随机效果,一个构造方法带有随机种子的参数,一个则没有,原理和上面是一样的:

public Random(); public Random(int Seed);

这个时候改变的就是System.Random类的随机方法,而非UnityEngine.Random的随机方法。

所以一开始就决定好整个开发过程中用的随机类也不容忽视,建议要么就全部用Unity中的,要么就全部用System中的,这样调整起来自然更得心应手事半功倍。

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=12ri51jwydxyj

Unity 随机数与随机种子的更多相关文章

  1. [C++基础]随机数,随机种子数

    #include <stdlib.h> #include <iostream> #include <ctime> using namespace std; void ...

  2. [改善Java代码]不要随便设置随机种子

    建议30: 不要随便设置随机种子 随机数在太多的地方使用了,比如加密.混淆数据等,我们使用随机数是期望获得一个唯一的.不可仿造的数字,以避免产生相同的业务数据造成混乱.在Java项目中通常是通过Mat ...

  3. Java Random随机种子

    第一种情况 Random rand = new Random(47); for(int i=0;i<10;i++) System.out.println(rand.nextInt(100)); ...

  4. c++ rand随机数生成(随机种子设置)

    需求:每次初始化不同的随机数 1.默认 //这样用每次都会产生相同数字 #include <stdlib.h> #include <stdio.h> #define N 10 ...

  5. Pytorch随机种子

    最近在做比赛的时候,遇到了一个最好结果,但是之后无论怎样都复现不出来最好结果了.猜测是不是跟Pytorch中的随机种子有关. 训练过程 在训练过程中,若相同的数据数据集,相同的训练集.测试集划分方式, ...

  6. shell 生成指定范围随机数与随机字符串 .

    shell 生成指定范围随机数与随机字符串         分类:             shell              2014-04-22 22:17     20902人阅读     评 ...

  7. random and password 在Linux下生成crypt加密密码的方法,shell 生成指定范围随机数与随机字符串

    openssl rand -hex n (n is number of characters) LANG=c < /dev/urandom tr -dc _A-Z-a-z-0-9 | head ...

  8. BZOJ2296: 【POJ Challenge】随机种子

    2296: [POJ Challenge]随机种子 Time Limit: 1 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 114  Solv ...

  9. [BZOJ2296] [POJ Challenge] 随机种子

    Description 1tthinking除了随机算法,其他什么都不会.但是他还是可以ac很多题目,他用的是什么呢?他会选择一个好的随机种子,然后输出答案.往往他选择的一个好的种子可以有99%的概率 ...

随机推荐

  1. c socket 开发测试

    c语言异常 参照他人代码写一个tcp的 socket 开发测试 异常A,在mac osx系统下编译失败,缺库转到debian下. 异常B,include引用文件顺序不对,编译大遍异常 异常C,/usr ...

  2. 吴裕雄--天生自然HTML学习笔记:HTML 表格

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 吴裕雄--天生自然 R语言开发学习:高级数据管理(续三)

    #-----------------------------------# # R in Action (2nd ed): Chapter 5 # # Advanced data management ...

  4. Scarpy框架安装教程

    在一切之前,建议升级pip,如果版本太低,安装会失败 升级pip命令: python -m pip install --upgrade pip 如果上面的命令不能用,用下面这个 easy_instal ...

  5. 监控Linux系统所选的服务所占进程内存占用

    [代码] #!/bin/bash #程序功能描述: # 监控系统所选的服务所占进程内存占用 #作者:孤舟点点 #版本:1.0 #创建时间:-- :: PATH=/bin:/sbin:/usr/bin: ...

  6. HTC新机A9足以取代iPhone 你相信吗?

    你相信吗?" title="HTC新机A9足以取代iPhone 你相信吗?"> 自信和嘴硬之间,往往就是成功与失败的分水岭.乔老爷子当年推出iPhone.iPad等 ...

  7. WiredTiger运行时参数优化

    MongoDB的WiredTiger存储引擎,用了一段时间,遇到了一些问题,通过优化WT参数,也解决了一些问题,做个小结. cache_size 指定WT存储引擎内部cache的内存用量上限. 需要注 ...

  8. C:数组习题

    与字符串处理有关的函数: 头文件:<stdio.h>    gets().puts() 头文件:<string.h> (1).字符串长度测量函数  :strlen(字符数组名) ...

  9. Ubuntu18.04LTS安装docker报错:Command 'lsb_release' not found

    Ubuntu18.04LTS安装docker在执行sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/ ...

  10. 大厂面试官问你META-INF/spring.factories要怎么实现自动扫描、自动装配?

    大厂面试官问你META-INF/spring.factories要怎么实现自动扫描.自动装配?   很多程序员想面试进互联网大厂,但是也有很多人不知道进入大厂需要具备哪些条件,以及面试官会问哪些问题, ...