random_number_generation.rst 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. .. _doc_random_number_generation:
  2. Random number generation
  3. ========================
  4. Many games rely on randomness to implement core game mechanics. This page
  5. guides you through common types of randomness and how to implement them in
  6. Godot.
  7. After giving you a brief overview of useful functions that generate random
  8. numbers, you will learn how to get random elements from arrays, dictionaries,
  9. and how to use a noise generator in GDScript. Lastly, we'll take a look at
  10. cryptographically secure random number generation and how it differs from
  11. typical random number generation.
  12. .. note::
  13. Computers cannot generate "true" random numbers. Instead, they rely on
  14. `pseudorandom number generators
  15. <https://en.wikipedia.org/wiki/Pseudorandom_number_generator>`__ (PRNGs).
  16. Godot internally uses the `PCG Family <https://www.pcg-random.org/>`__
  17. of pseudorandom number generators.
  18. Global scope versus RandomNumberGenerator class
  19. -----------------------------------------------
  20. Godot exposes two ways to generate random numbers: via *global scope* methods or
  21. using the :ref:`class_RandomNumberGenerator` class.
  22. Global scope methods are easier to set up, but they don't offer as much control.
  23. RandomNumberGenerator requires more code to use, but allows creating
  24. multiple instances, each with their own seed and state.
  25. This tutorial uses global scope methods, except when the method only exists in
  26. the RandomNumberGenerator class.
  27. The randomize() method
  28. ----------------------
  29. .. note::
  30. Since Godot 4.0, the random seed is automatically set to a random value when
  31. the project starts. This means you don't need to call ``randomize()`` in
  32. ``_ready()`` anymore to ensure that results are random across project runs.
  33. However, you can still use ``randomize()`` if you want to use a specific
  34. seed number, or generate it using a different method.
  35. In global scope, you can find a :ref:`randomize()
  36. <class_@GlobalScope_method_randomize>` method. **This method should be called only
  37. once when your project starts to initialize the random seed.** Calling it
  38. multiple times is unnecessary and may impact performance negatively.
  39. Putting it in your main scene script's ``_ready()`` method is a good choice:
  40. .. tabs::
  41. .. code-tab:: gdscript GDScript
  42. func _ready():
  43. randomize()
  44. .. code-tab:: csharp
  45. public override void _Ready()
  46. {
  47. GD.Randomize();
  48. }
  49. You can also set a fixed random seed instead using :ref:`seed()
  50. <class_@GlobalScope_method_seed>`. Doing so will give you *deterministic* results
  51. across runs:
  52. .. tabs::
  53. .. code-tab:: gdscript GDScript
  54. func _ready():
  55. seed(12345)
  56. # To use a string as a seed, you can hash it to a number.
  57. seed("Hello world".hash())
  58. .. code-tab:: csharp
  59. public override void _Ready()
  60. {
  61. GD.Seed(12345);
  62. // To use a string as a seed, you can hash it to a number.
  63. GD.Seed("Hello world".Hash());
  64. }
  65. When using the RandomNumberGenerator class, you should call ``randomize()`` on
  66. the instance since it has its own seed:
  67. .. tabs::
  68. .. code-tab:: gdscript GDScript
  69. var random = RandomNumberGenerator.new()
  70. random.randomize()
  71. .. code-tab:: csharp
  72. var random = new RandomNumberGenerator();
  73. random.Randomize();
  74. Getting a random number
  75. -----------------------
  76. Let's look at some of the most commonly used functions and methods to generate
  77. random numbers in Godot.
  78. The function :ref:`randi() <class_@GlobalScope_method_randi>` returns a random
  79. number between ``0`` and ``2^32 - 1``. Since the maximum value is huge, you most
  80. likely want to use the modulo operator (``%``) to bound the result between 0 and
  81. the denominator:
  82. .. tabs::
  83. .. code-tab:: gdscript GDScript
  84. # Prints a random integer between 0 and 49.
  85. print(randi() % 50)
  86. # Prints a random integer between 10 and 60.
  87. print(randi() % 51 + 10)
  88. .. code-tab:: csharp
  89. // Prints a random integer between 0 and 49.
  90. GD.Print(GD.Randi() % 50);
  91. // Prints a random integer between 10 and 60.
  92. GD.Print(GD.Randi() % 51 + 10);
  93. :ref:`randf() <class_@GlobalScope_method_randf>` returns a random floating-point
  94. number between 0 and 1. This is useful to implement a
  95. :ref:`doc_random_number_generation_weighted_random_probability` system, among
  96. other things.
  97. :ref:`randfn() <class_@GlobalScope_method_randfn>` returns a random
  98. floating-point number following a `normal distribution
  99. <https://en.wikipedia.org/wiki/Normal_distribution>`__. This means the returned
  100. value is more likely to be around the mean (0.0 by default),
  101. varying by the deviation (1.0 by default):
  102. .. tabs::
  103. .. code-tab:: gdscript GDScript
  104. # Prints a random floating-point number from a normal distribution with a mean 0.0 and deviation 1.0.
  105. print(randfn(0.0, 1.0))
  106. .. code-tab:: csharp
  107. // Prints a random floating-point number from a normal distribution with a mean 0.0 and deviation 1.0.
  108. GD.Print(GD.Randfn(0.0, 1.0));
  109. :ref:`randf_range() <class_@GlobalScope_method_randf_range>` takes two arguments
  110. ``from`` and ``to``, and returns a random floating-point number between ``from``
  111. and ``to``:
  112. .. tabs::
  113. .. code-tab:: gdscript GDScript
  114. # Prints a random floating-point number between -4 and 6.5.
  115. print(randf_range(-4, 6.5))
  116. .. code-tab:: csharp
  117. // Prints a random floating-point number between -4 and 6.5.
  118. GD.Print(GD.RandRange(-4.0, 6.5));
  119. :ref:`randi_range() <class_@GlobalScope_method_randi_range>` takes two arguments ``from``
  120. and ``to``, and returns a random integer between ``from`` and ``to``:
  121. .. tabs::
  122. .. code-tab:: gdscript GDScript
  123. # Prints a random integer between -10 and 10.
  124. print(randi_range(-10, 10))
  125. .. code-tab:: csharp
  126. // Prints a random integer number between -10 and 10.
  127. GD.Print(GD.RandRange(-10, 10));
  128. Get a random array element
  129. --------------------------
  130. We can use random integer generation to get a random element from an array,
  131. or use the :ref:`Array.pick_random<class_Array_method_pick_random>` method
  132. to do it for us:
  133. .. tabs::
  134. .. code-tab:: gdscript GDScript
  135. var _fruits = ["apple", "orange", "pear", "banana"]
  136. func _ready():
  137. for i in range(100):
  138. # Pick 100 fruits randomly.
  139. print(get_fruit())
  140. for i in range(100):
  141. # Pick 100 fruits randomly, this time using the `Array.pick_random()`
  142. # helper method. This has the same behavior as `get_fruit()`.
  143. print(_fruits.pick_random())
  144. func get_fruit():
  145. var random_fruit = _fruits[randi() % _fruits.size()]
  146. # Returns "apple", "orange", "pear", or "banana" every time the code runs.
  147. # We may get the same fruit multiple times in a row.
  148. return random_fruit
  149. .. code-tab:: csharp
  150. // Use Godot's Array type instead of a BCL type so we can use `PickRandom()` on it.
  151. private Godot.Collections.Array<string> _fruits = ["apple", "orange", "pear", "banana"];
  152. public override void _Ready()
  153. {
  154. for (int i = 0; i < 100; i++)
  155. {
  156. // Pick 100 fruits randomly.
  157. GD.Print(GetFruit());
  158. }
  159. for (int i = 0; i < 100; i++)
  160. {
  161. // Pick 100 fruits randomly, this time using the `Array.PickRandom()`
  162. // helper method. This has the same behavior as `GetFruit()`.
  163. GD.Print(_fruits.PickRandom());
  164. }
  165. }
  166. public string GetFruit()
  167. {
  168. string randomFruit = _fruits[GD.Randi() % _fruits.Size()];
  169. // Returns "apple", "orange", "pear", or "banana" every time the code runs.
  170. // We may get the same fruit multiple times in a row.
  171. return randomFruit;
  172. }
  173. To prevent the same fruit from being picked more than once in a row, we can add
  174. more logic to the above method. In this case, we can't use
  175. :ref:`Array.pick_random<class_Array_method_pick_random>` since it lacks a way to
  176. prevent repetition:
  177. .. tabs::
  178. .. code-tab:: gdscript GDScript
  179. var _fruits = ["apple", "orange", "pear", "banana"]
  180. var _last_fruit = ""
  181. func _ready():
  182. # Pick 100 fruits randomly.
  183. for i in range(100):
  184. print(get_fruit())
  185. func get_fruit():
  186. var random_fruit = _fruits[randi() % _fruits.size()]
  187. while random_fruit == _last_fruit:
  188. # The last fruit was picked. Try again until we get a different fruit.
  189. random_fruit = _fruits[randi() % _fruits.size()]
  190. # Note: if the random element to pick is passed by reference,
  191. # such as an array or dictionary,
  192. # use `_last_fruit = random_fruit.duplicate()` instead.
  193. _last_fruit = random_fruit
  194. # Returns "apple", "orange", "pear", or "banana" every time the code runs.
  195. # The function will never return the same fruit more than once in a row.
  196. return random_fruit
  197. .. code-tab:: csharp
  198. private string[] _fruits = ["apple", "orange", "pear", "banana"];
  199. private string _lastFruit = "";
  200. public override void _Ready()
  201. {
  202. for (int i = 0; i < 100; i++)
  203. {
  204. // Pick 100 fruits randomly.
  205. GD.Print(GetFruit());
  206. }
  207. }
  208. public string GetFruit()
  209. {
  210. string randomFruit = _fruits[GD.Randi() % _fruits.Length];
  211. while (randomFruit == _lastFruit)
  212. {
  213. // The last fruit was picked. Try again until we get a different fruit.
  214. randomFruit = _fruits[GD.Randi() % _fruits.Length];
  215. }
  216. _lastFruit = randomFruit;
  217. // Returns "apple", "orange", "pear", or "banana" every time the code runs.
  218. // The function will never return the same fruit more than once in a row.
  219. return randomFruit;
  220. }
  221. This approach can be useful to make random number generation feel less
  222. repetitive. Still, it doesn't prevent results from "ping-ponging" between a
  223. limited set of values. To prevent this, use the :ref:`shuffle bag
  224. <doc_random_number_generation_shuffle_bags>` pattern instead.
  225. Get a random dictionary value
  226. -----------------------------
  227. We can apply similar logic from arrays to dictionaries as well:
  228. .. tabs::
  229. .. code-tab:: gdscript GDScript
  230. var _metals = {
  231. "copper": {"quantity": 50, "price": 50},
  232. "silver": {"quantity": 20, "price": 150},
  233. "gold": {"quantity": 3, "price": 500},
  234. }
  235. func _ready():
  236. for i in range(20):
  237. print(get_metal())
  238. func get_metal():
  239. var random_metal = _metals.values()[randi() % metals.size()]
  240. # Returns a random metal value dictionary every time the code runs.
  241. # The same metal may be selected multiple times in succession.
  242. return random_metal
  243. .. code-tab:: csharp
  244. private Godot.Collections.Dictionary<string, Godot.Collections.Dictionary<string, int>> _metals = new()
  245. {
  246. {"copper", new Godot.Collections.Dictionary<string, int>{{"quantity", 50}, {"price", 50}}},
  247. {"silver", new Godot.Collections.Dictionary<string, int>{{"quantity", 20}, {"price", 150}}},
  248. {"gold", new Godot.Collections.Dictionary<string, int>{{"quantity", 3}, {"price", 500}}},
  249. };
  250. public override void _Ready()
  251. {
  252. for (int i = 0; i < 20; i++)
  253. {
  254. GD.Print(GetMetal());
  255. }
  256. }
  257. public Godot.Collections.Dictionary<string, int> GetMetal()
  258. {
  259. var (_, randomMetal) = _metals.ElementAt((int)(GD.Randi() % _metals.Count));
  260. // Returns a random metal value dictionary every time the code runs.
  261. // The same metal may be selected multiple times in succession.
  262. return randomMetal;
  263. }
  264. .. _doc_random_number_generation_weighted_random_probability:
  265. Weighted random probability
  266. ---------------------------
  267. The :ref:`randf() <class_@GlobalScope_method_randf>` method returns a
  268. floating-point number between 0.0 and 1.0. We can use this to create a
  269. "weighted" probability where different outcomes have different likelihoods:
  270. .. tabs::
  271. .. code-tab:: gdscript GDScript
  272. func _ready():
  273. for i in range(100):
  274. print(get_item_rarity())
  275. func get_item_rarity():
  276. var random_float = randf()
  277. if random_float < 0.8:
  278. # 80% chance of being returned.
  279. return "Common"
  280. elif random_float < 0.95:
  281. # 15% chance of being returned.
  282. return "Uncommon"
  283. else:
  284. # 5% chance of being returned.
  285. return "Rare"
  286. .. code-tab:: csharp
  287. public override void _Ready()
  288. {
  289. for (int i = 0; i < 100; i++)
  290. {
  291. GD.Print(GetItemRarity());
  292. }
  293. }
  294. public string GetItemRarity()
  295. {
  296. float randomFloat = GD.Randf();
  297. if (randomFloat < 0.8f)
  298. {
  299. // 80% chance of being returned.
  300. return "Common";
  301. }
  302. else if (randomFloat < 0.95f)
  303. {
  304. // 15% chance of being returned.
  305. return "Uncommon";
  306. }
  307. else
  308. {
  309. // 5% chance of being returned.
  310. return "Rare";
  311. }
  312. }
  313. You can also get a weighted random *index* using the
  314. :ref:`rand_weighted() <class_RandomNumberGenerator_method_rand_weighted>` method
  315. on a RandomNumberGenerator instance. This returns a random integer
  316. between 0 and the size of the array that is passed as a parameter. Each value in the
  317. array is a floating-point number that represents the *relative* likelihood that it
  318. will be returned as an index. A higher value means the value is more likely to be
  319. returned as an index, while a value of ``0`` means it will never be returned as an index.
  320. For example, if ``[0.5, 1, 1, 2]`` is passed as a parameter, then the method is twice
  321. as likely to return ``3`` (the index of the value ``2``) and twice as unlikely to return
  322. ``0`` (the index of the value ``0.5``) compared to the indices ``1`` and ``2``.
  323. Since the returned value matches the array's size, it can be used as an index to
  324. get a value from another array as follows:
  325. .. tabs::
  326. .. code-tab:: gdscript GDScript
  327. # Prints a random element using the weighted index that is returned by `rand_weighted()`.
  328. # Here, "apple" will be returned twice as rarely as "orange" and "pear".
  329. # "banana" is twice as common as "orange" and "pear", and four times as common as "apple".
  330. var fruits = ["apple", "orange", "pear", "banana"]
  331. var probabilities = [0.5, 1, 1, 2];
  332. var random = RandomNumberGenerator.new()
  333. print(fruits[random.rand_weighted(probabilities)])
  334. .. code-tab:: csharp
  335. // Prints a random element using the weighted index that is returned by `RandWeighted()`.
  336. // Here, "apple" will be returned twice as rarely as "orange" and "pear".
  337. // "banana" is twice as common as "orange" and "pear", and four times as common as "apple".
  338. string[] fruits = ["apple", "orange", "pear", "banana"];
  339. float[] probabilities = [0.5f, 1, 1, 2];
  340. var random = new RandomNumberGenerator();
  341. GD.Print(fruits[random.RandWeighted(probabilities)]);
  342. .. _doc_random_number_generation_shuffle_bags:
  343. "Better" randomness using shuffle bags
  344. --------------------------------------
  345. Taking the same example as above, we would like to pick fruits at random.
  346. However, relying on random number generation every time a fruit is selected can
  347. lead to a less *uniform* distribution. If the player is lucky (or unlucky), they
  348. could get the same fruit three or more times in a row.
  349. You can accomplish this using the *shuffle bag* pattern. It works by removing an
  350. element from the array after choosing it. After multiple selections, the array
  351. ends up empty. When that happens, you reinitialize it to its default value:
  352. .. tabs::
  353. .. code-tab:: gdscript GDScript
  354. var _fruits = ["apple", "orange", "pear", "banana"]
  355. # A copy of the fruits array so we can restore the original value into `fruits`.
  356. var _fruits_full = []
  357. func _ready():
  358. _fruits_full = _fruits.duplicate()
  359. _fruits.shuffle()
  360. for i in 100:
  361. print(get_fruit())
  362. func get_fruit():
  363. if _fruits.is_empty():
  364. # Fill the fruits array again and shuffle it.
  365. _fruits = _fruits_full.duplicate()
  366. _fruits.shuffle()
  367. # Get a random fruit, since we shuffled the array,
  368. # and remove it from the `_fruits` array.
  369. var random_fruit = _fruits.pop_front()
  370. # Returns "apple", "orange", "pear", or "banana" every time the code runs, removing it from the array.
  371. # When all fruit are removed, it refills the array.
  372. return random_fruit
  373. .. code-tab:: csharp
  374. private Godot.Collections.Array<string> _fruits = ["apple", "orange", "pear", "banana"];
  375. // A copy of the fruits array so we can restore the original value into `fruits`.
  376. private Godot.Collections.Array<string> _fruitsFull;
  377. public override void _Ready()
  378. {
  379. _fruitsFull = _fruits.Duplicate();
  380. _fruits.Shuffle();
  381. for (int i = 0; i < 100; i++)
  382. {
  383. GD.Print(GetFruit());
  384. }
  385. }
  386. public string GetFruit()
  387. {
  388. if(_fruits.Count == 0)
  389. {
  390. // Fill the fruits array again and shuffle it.
  391. _fruits = _fruitsFull.Duplicate();
  392. _fruits.Shuffle();
  393. }
  394. // Get a random fruit, since we shuffled the array,
  395. string randomFruit = _fruits[0];
  396. // and remove it from the `_fruits` array.
  397. _fruits.RemoveAt(0);
  398. // Returns "apple", "orange", "pear", or "banana" every time the code runs, removing it from the array.
  399. // When all fruit are removed, it refills the array.
  400. return randomFruit;
  401. }
  402. When running the above code, there is a chance to get the same fruit twice in a
  403. row. Once we picked a fruit, it will no longer be a possible return value unless
  404. the array is now empty. When the array is empty, we reset it back to its default
  405. value, making it possible to have the same fruit again, but only once.
  406. Random noise
  407. ------------
  408. The random number generation shown above can show its limits when you need a
  409. value that *slowly* changes depending on the input. The input can be a position,
  410. time, or anything else.
  411. To achieve this, you can use random *noise* functions. Noise functions are
  412. especially popular in procedural generation to generate realistic-looking
  413. terrain. Godot provides :ref:`class_fastnoiselite` for this, which supports
  414. 1D, 2D and 3D noise. Here's an example with 1D noise:
  415. .. tabs::
  416. .. code-tab:: gdscript GDScript
  417. var _noise = FastNoiseLite.new()
  418. func _ready():
  419. # Configure the FastNoiseLite instance.
  420. _noise.noise_type = FastNoiseLite.NoiseType.TYPE_SIMPLEX_SMOOTH
  421. _noise.seed = randi()
  422. _noise.fractal_octaves = 4
  423. _noise.frequency = 1.0 / 20.0
  424. for i in 100:
  425. # Prints a slowly-changing series of floating-point numbers
  426. # between -1.0 and 1.0.
  427. print(_noise.get_noise_1d(i))
  428. .. code-tab:: csharp
  429. private FastNoiseLite _noise = new FastNoiseLite();
  430. public override void _Ready()
  431. {
  432. // Configure the FastNoiseLite instance.
  433. _noise.NoiseType = FastNoiseLite.NoiseTypeEnum.SimplexSmooth;
  434. _noise.Seed = (int)GD.Randi();
  435. _noise.FractalOctaves = 4;
  436. _noise.Frequency = 1.0f / 20.0f;
  437. for (int i = 0; i < 100; i++)
  438. {
  439. GD.Print(_noise.GetNoise1D(i));
  440. }
  441. }
  442. Cryptographically secure pseudorandom number generation
  443. -------------------------------------------------------
  444. So far, the approaches mentioned above are **not** suitable for
  445. *cryptographically secure* pseudorandom number generation (CSPRNG). This is fine
  446. for games, but this is not sufficient for scenarios where encryption,
  447. authentication or signing is involved.
  448. Godot offers a :ref:`class_Crypto` class for this. This class can perform
  449. asymmetric key encryption/decryption, signing/verification, while also
  450. generating cryptographically secure random bytes, RSA keys, HMAC digests, and
  451. self-signed :ref:`class_X509Certificate`\ s.
  452. The downside of :abbr:`CSPRNG (Cryptographically secure pseudorandom number generation)`
  453. is that it's much slower than standard pseudorandom number generation. Its API
  454. is also less convenient to use. As a result,
  455. :abbr:`CSPRNG (Cryptographically secure pseudorandom number generation)`
  456. should be avoided for gameplay elements.
  457. Example of using the Crypto class to generate 2 random integers between ``0``
  458. and ``2^32 - 1`` (inclusive):
  459. ::
  460. var crypto := Crypto.new()
  461. # Request as many bytes as you need, but try to minimize the amount
  462. # of separate requests to improve performance.
  463. # Each 32-bit integer requires 4 bytes, so we request 8 bytes.
  464. var byte_array := crypto.generate_random_bytes(8)
  465. # Use the ``decode_u32()`` method from PackedByteArray to decode a 32-bit unsigned integer
  466. # from the beginning of `byte_array`. This method doesn't modify `byte_array`.
  467. var random_int_1 := byte_array.decode_u32(0)
  468. # Do the same as above, but with an offset of 4 bytes since we've already decoded
  469. # the first 4 bytes previously.
  470. var random_int_2 := byte_array.decode_u32(4)
  471. prints("Random integers:", random_int_1, random_int_2)
  472. .. seealso::
  473. See :ref:`class_PackedByteArray`'s documentation for other methods you can
  474. use to decode the generated bytes into various types of data, such as
  475. integers or floats.