随机数几乎应用于游戏开发的方方面面,例如,随机生成的地图,迷宫,怪物属性等,在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. A 小石的签到题

    题目链接:https://ac.nowcoder.com/acm/contest/949/A 思路: 这题明确的说了是个签到题,但是一直怀疑不是签到题,是唬我的,结果仔细想了想真是这么回事. 每个人必 ...

  2. HOG算法基础

    实现思路步骤: 1.对原图像gamma校正,img=sqrt(img); 2.求图像竖直边缘,水平边缘,边缘强度,边缘斜率. 3.将图像每16*16(取其他也可以)个像素分到一个cell中.对于256 ...

  3. LeetCode Day 6

    LeetCode0006 将一个给定字符串根据给定的行数,以从上往下.从左到右进行 Z 字形排列. 比如输入字符串为 "LEETCODEISHIRING" ,指定行数为 3 时,排 ...

  4. 密码子演化假说|凝固事件假说|立体化学假说|共进化假说|代谢途径相关性假说|四重兼并|假四重兼并|最小损伤原则|AU-rich|GC-rich|逐步进化假说|分子机制进化假说

    生命组学 将密码子表重排后发现,嘌呤嘧啶含量不同,密码子的氨基酸种类由第一二位决定,同时第三位变化大却没有蛋白质层面上实质性的改变,这说明第三位氨基酸是用于维持氨基酸组成不发生变化同时保证蛋白质稳定性 ...

  5. navisworks安装未完成,某些产品无法安装的解决方法

    navisworks提示安装未完成,某些产品无法安装该怎样解决呢?,一些朋友在win7或者win10系统下安装navisworks失败提示navisworks安装未完成,某些产品无法安装,也有时候想重 ...

  6. IO流框架

    目录 IO流框架总结 字节流 字符流 IO流框架总结 普通IO / NIO 字节流 字节流是万能流,但是在处理字符方面有时候不太方便,一般用来处理二进制文件 字节输入流 InputStream int ...

  7. eclipse中maven项目failonmissingwebxml错误的修复(转)

    在使用eclipse创建maven项目的时候,有时候会出现这个问题: web.xml is missing and 'failOnMissingWebXml' is set to true我遇到这个问 ...

  8. 修改 commit message

    本文为原创文章,转载请标明出处 目录 修改上一条提交的 commit message 修改之前提交的 commit message 1. 修改上一条提交的 commit message git com ...

  9. unittest(6)- 作业- 测试类中写多个函数

    实践作业:对多个接口发起请求,测试类中写多个测试函数 # 1. http_request import requests class HttpRequest: def http_request(sel ...

  10. python 学员管理系统

    需求: 用户角色,讲师\学员, 用户登陆后根据角色不同,能做的事情不同,分别如下 讲师视图 管理班级,可创建班级,根据学员qq号把学员加入班级 可创建指定班级的上课纪录,注意一节上课纪录对应多条学员的 ...