随机数几乎应用于游戏开发的方方面面,例如,随机生成的地图,迷宫,怪物属性等,在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. MOOC(7)- case依赖、读取json配置文件进行多个接口请求-模拟接口响应数据(18)

    这里是把传入的请求数据作为响应值返回 # -*- coding: utf-8 -*- # @Time : 2020/2/15 9:47 # @File : do_mock_18.py # @Autho ...

  2. 最优化算法——常见优化算法分类及总结

    之前做特征选择,实现过基于群智能算法进行最优化的搜索,看过一些群智能优化算法的论文,在此做一下总结. 在生活或者工作中存在各种各样的最优化问题,比如每个企业和个人都要考虑的一个问题"在一定成 ...

  3. git使用的简要介绍

    GIT """ 什么是git:版本控制器 - 控制的对象是开发的项目代码 代码开发时间轴:需求1 > 版本库1 > 需求2 > 版本库2 > 版本 ...

  4. vm文件的优点

    vm文件的优点 相较于内容写在jsp 文件: 1.在网页上上浏览和下载的内容用的是同一套,也就是说只需要维护一套内容,页面上看到的和下载得到的是一致的. 2.版本控制较为简便, 实现了页面内容和jsp ...

  5. Angular2与Angular1的区别

    原文地址: http://www.angularjs.cn/A2Ar 整体上来说,Angular2变得更加简洁,最核心的概念只剩下一个,那就是组件Component,其它所有的一切都是围绕着Compo ...

  6. 张益肇:AI 医疗,微软有哪些布局?

    编者按:近几年来,医疗和人工智能碰撞出了相当多的火花,大量资金短期投入到医疗领域当中.然而在微软亚洲研究院副院长张益肇博士看来,人工智能医疗是一场持久战,大家一定要沉下心多调研.多思考.多学习. 人工 ...

  7. C++走向远洋——68(十六周、文件)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  8. C++走向远洋——41(深复制体验,3,)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  9. 远程桌面协议RDP

    远程桌面协议RDP(Remove Desktop Protocol) 通过mstsc客户端远程连接计算机,并对其进行管理等操作. 与TELNET的区别在于,TELNET显示的是远程计算机的命令行窗口, ...

  10. USB小白学习之路(2)端点IN/OUT互换

    端点2(out)和端点6(in)的out_in互换 注:这里的out和in都是以host为标准说的,out是host的out,在设备(Cy7c68013)这里其实是输入端口:in是host的in,在设 ...