概述

计算机程序是精确的艺术,现实生活却充满了随机性。如果你的游戏缺乏了随机性,也就缺乏了最基础的乐趣。

我们在很多场景下需要使用随机数,来为已经非常刻意和规整的设计带来一些变化和趣味。

比如打怪、打完Boss或开宝箱后随机掉落不同的物品,随机生成地图,判定某次攻击的命中率等等。

要想成为游戏设计高手,随机数的学习和使用是躲不开的命题。

本篇讲解Godot内置脚本GDScript提供的随机数生成类和方法,带你进入游戏设计随机数的大门。

真随机数和伪随机数

基本定义

在这之前需要先明白一点:随机数都是由随机数生成器(Random Number Generator)生成的。

真随机数(TRUE Random Number)

真正的随机数是使用物理现象产生的:比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等等,这样的随机数发生器叫做物理性随机数发生器,它们的缺点是技术要求比较高。 ----百度百科

伪随机数(Pseudo-Random Number)

真正意义上的随机数(或者随机事件)在某次产生过程中是按照实验过程中表现的分布概率随机产生的,其结果是不可预测的,是不可见的。

而计算机中的随机函数是按照一定算法模拟产生的,其结果是确定的,是可见的。我们可以这样认为这个可预见的结果其出现的概率是100%。所以用计算机随机函数所产生的“随机数”并不随机,是伪随机数。

从定义我们可以了解到,伪随机数其实是有规律的。只不过这个规律周期比较长,但还是可以预测的。主要原因就是伪随机数是计算机使用算法模拟出来的,这个过程并不涉及到物理过程,所以自然不可能具有真随机数的特性。

在GDScript中使用随机数

GDScript提供了一个名叫RandomNumberGenerator的类用于生成随机数,直译过来就是“随机数生成器”。下图是它的一个简要总结图。
在这里插入图片描述

extends Node2D

var rng = RandomNumberGenerator.new()

func _ready():
	rng.randomize()    # 为RNG设置基于时间的种子
	print(rng.randi()) # 生成整数
	pass

以上的代码生成的是一个比较大的随机整数。

  • randi()中的i就是int或者integer,也就是“整数”意思。
  • 你可以看到还有一个函数randf(),它的f,就是float,“浮点数”的意思。

这样理解和记忆起来就不会费劲了。

randi()

值得注意的是,randi()只会生成无符号整数,也就是始终返回一个正整数。

因为它返回的数比较大,所以要限定其范围获得一个比较小的数,就需要用运算符%,后面跟一个整数。这是一种特定的写法:

rng.randi()            # 返回 02^32 - 1 之间的随机整数
rng.randi() % 20       # 返回019之间的随机整数
rng.randi() % 20 + 1   # 返回120之间的随机整数
rng.randi() % 100      # 返回099之间的随机整数
rng.randi() % 100 + 1  # 返回1100之间的随机整数

randf()

randf()返回的是0.01.0之间的小数,print出来的是带六位小数的浮点数。

如果想要获得一个大一点的数,就需要在randf()之上乘以一个整数。

rng.randf() * 10 # 返回0-10之间的浮点数

randi_range()和randf_range()

很多时候我们只需要一个小范围内的随机数。可以使用带_range后缀的两个方法来限定范围。

rng.randi_range(1,10)
rng.randi_range(-10,10)
rng.randf_range(1.0,10.0)
rng.randf_range(-10.0,10.0)

randomize()的作用

  • RandomNumberGenerator生成伪随机数是靠“随机数种子”。
  • randomize()的作用是生成一个基于时间的随机数种子,只要这个随机数种子发生了变化,用其方法生成的伪随机数才会发生变化,否则,返回的还是之前的随机数数列。

随机数生成器的状态

RandomNumberGeneratorstate属性是一个整数值,保存了它的状态,有点像随机数种子,只要我们记录和恢复了它,也就意为着可以还原整个随机数生成器的状态,生成一模一样的随机数数列。

var rng = RandomNumberGenerator.new()
print(rng.randf())
var saved_state = rng.state    # 存储当前状态。
print(rng.randf())             # 提前进入内部状态。
rng.state = saved_state        # 存储状态
print(rng.randf())             # 打印与上一次相同的值。

@GDScript内置的相关随机数生成函数

GDScript内置函数里,有几个和RandomNumberGenerator方法近乎一致的一些方法,我们可以直接拿来使用。
在这里插入图片描述

参考

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐