random_number_generation.rst 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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.
  10. .. note::
  11. Computers cannot generate "true" random numbers. Instead, they rely on
  12. `pseudorandom number generators
  13. <https://en.wikipedia.org/wiki/Pseudorandom_number_generator>`__ (PRNGs).
  14. Global scope versus RandomNumberGenerator class
  15. -----------------------------------------------
  16. Godot exposes two ways to generate random numbers: via *global scope* methods or
  17. using the :ref:`class_RandomNumberGenerator` class.
  18. Global scope methods are easier to set up, but they don't offer as much control.
  19. RandomNumberGenerator requires more code to use, but exposes many methods not
  20. found in global scope such as :ref:`randi_range()
  21. <class_RandomNumberGenerator_method_randi_range>` and :ref:`randfn()
  22. <class_RandomNumberGenerator_method_randfn>`. On top of that, it allows creating
  23. multiple instances each with their own seed.
  24. This tutorial uses global scope methods, except when the method only exists in
  25. the RandomNumberGenerator class.
  26. The randomize() method
  27. ----------------------
  28. In global scope, you can find a :ref:`randomize()
  29. <class_@GDScript_method_randomize>` method. **This method should be called only
  30. once when your project starts to initialize the random seed.** Calling it
  31. multiple times is unnecessary and may impact performance negatively.
  32. Putting it in your main scene script's ``_ready()`` method is a good choice:
  33. .. tabs::
  34. .. code-tab:: gdscript GDScript
  35. func _ready():
  36. randomize()
  37. .. code-tab:: csharp
  38. public override void _Ready()
  39. {
  40. GD.Randomize();
  41. }
  42. You can also set a fixed random seed instead using :ref:`seed()
  43. <class_@GDScript_method_seed>`. Doing so will give you *deterministic* results
  44. across runs:
  45. .. tabs::
  46. .. code-tab:: gdscript GDScript
  47. func _ready():
  48. seed(12345)
  49. # To use a string as a seed, you can hash it to a number.
  50. seed("Hello world".hash())
  51. .. code-tab:: csharp
  52. public override void _Ready()
  53. {
  54. GD.Seed(12345);
  55. GD.Seed("Hello world".Hash());
  56. }
  57. When using the RandomNumberGenerator class, you should call ``randomize()`` on
  58. the instance since it has its own seed:
  59. .. tabs::
  60. .. code-tab:: gdscript GDScript
  61. var random = RandomNumberGenerator.new()
  62. random.randomize()
  63. .. code-tab:: csharp
  64. var random = new RandomNumberGenerator();
  65. random.Randomize();
  66. Getting a random number
  67. -----------------------
  68. Let's look at some of the most commonly used functions and methods to generate
  69. random numbers in Godot.
  70. The function :ref:`randi() <class_@GDScript_method_randi>` returns a random
  71. number between 0 and 2^32-1. Since the maximum value is huge, you most likely
  72. want to use the modulo operator (``%``) to bound the result between 0 and the
  73. denominator:
  74. .. tabs::
  75. .. code-tab:: gdscript GDScript
  76. # Prints a random integer between 0 and 49.
  77. print(randi() % 50)
  78. # Prints a random integer between 10 and 60.
  79. print(randi() % 51 + 10)
  80. .. code-tab:: csharp
  81. // Prints a random integer between 0 and 49.
  82. GD.Print(GD.Randi() % 50);
  83. // Prints a random integer between 10 and 60.
  84. GD.Print(GD.Randi() % 51 + 10);
  85. :ref:`randf() <class_@GDScript_method_randf>` returns a random floating-point
  86. number between 0 and 1. This is useful to implement a
  87. :ref:`doc_random_number_generation_weighted_random_probability` system, among
  88. other things.
  89. :ref:`randfn() <class_RandomNumberGenerator_method_randfn>` returns a random
  90. floating-point number following a `normal distribution
  91. <https://en.wikipedia.org/wiki/Normal_distribution>`__. This means the returned
  92. value is more likely to be around the mean (0.0 by default),
  93. varying by the deviation (1.0 by default):
  94. .. tabs::
  95. .. code-tab:: gdscript GDScript
  96. # Prints a random floating-point number from a normal distribution with a mean 0.0 and deviation 1.0.
  97. var random = RandomNumberGenerator.new()
  98. random.randomize()
  99. print(random.randfn())
  100. .. code-tab:: csharp
  101. // Prints a normally distributed floating-point number between 0.0 and 1.0.
  102. var random = new RandomNumberGenerator();
  103. random.Randomize();
  104. GD.Print(random.Randfn());
  105. :ref:`rand_range() <class_@GDScript_method_rand_range>` takes two arguments
  106. ``from`` and ``to``, and returns a random floating-point number between ``from``
  107. and ``to``:
  108. .. tabs::
  109. .. code-tab:: gdscript GDScript
  110. # Prints a random floating-point number between -4 and 6.5.
  111. print(rand_range(-4, 6.5))
  112. .. code-tab:: csharp
  113. // Prints a random floating-point number between -4 and 6.5.
  114. GD.Print(GD.RandRange(-4, 6.5));
  115. :ref:`RandomNumberGenerator.randi_range()
  116. <class_RandomNumberGenerator_method_randi_range>` takes two arguments ``from``
  117. and ``to``, and returns a random integer between ``from`` and ``to``:
  118. .. tabs::
  119. .. code-tab:: gdscript GDScript
  120. # Prints a random integer between -10 and 10.
  121. var random = RandomNumberGenerator.new()
  122. random.randomize()
  123. print(random.randi_range(-10, 10))
  124. .. code-tab:: csharp
  125. // Prints a random integer number between -10 and 10.
  126. random.Randomize();
  127. GD.Print(random.RandiRange(-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. .. tabs::
  132. .. code-tab:: gdscript GDScript
  133. var _fruits = ["apple", "orange", "pear", "banana"]
  134. func _ready():
  135. randomize()
  136. for i in range(100):
  137. # Pick 100 fruits randomly.
  138. print(get_fruit())
  139. func get_fruit():
  140. var random_fruit = _fruits[randi() % _fruits.size()]
  141. # Returns "apple", "orange", "pear", or "banana" every time the code runs.
  142. # We may get the same fruit multiple times in a row.
  143. return random_fruit
  144. .. code-tab:: csharp
  145. private string[] _fruits = { "apple", "orange", "pear", "banana" };
  146. public override void _Ready()
  147. {
  148. GD.Randomize();
  149. for (int i = 0; i < 100; i++)
  150. {
  151. // Pick 100 fruits randomly.
  152. GD.Print(GetFruit());
  153. }
  154. }
  155. public string GetFruit()
  156. {
  157. string randomFruit = _fruits[GD.Randi() % _fruits.Length];
  158. // Returns "apple", "orange", "pear", or "banana" every time the code runs.
  159. // We may get the same fruit multiple times in a row.
  160. return randomFruit;
  161. }
  162. To prevent the same fruit from being picked more than once in a row, we can add
  163. more logic to this method:
  164. .. tabs::
  165. .. code-tab:: gdscript GDScript
  166. var _fruits = ["apple", "orange", "pear", "banana"]
  167. var _last_fruit = ""
  168. func _ready():
  169. randomize()
  170. # Pick 100 fruits randomly.
  171. for i in range(100):
  172. print(get_fruit())
  173. func get_fruit():
  174. var random_fruit = _fruits[randi() % _fruits.size()]
  175. while random_fruit == _last_fruit:
  176. # The last fruit was picked, try again until we get a different fruit.
  177. random_fruit = _fruits[randi() % _fruits.size()]
  178. # Note: if the random element to pick is passed by reference,
  179. # such as an array or dictionary,
  180. # use `_last_fruit = random_fruit.duplicate()` instead.
  181. _last_fruit = random_fruit
  182. # Returns "apple", "orange", "pear", or "banana" every time the code runs.
  183. # The function will never return the same fruit more than once in a row.
  184. return random_fruit
  185. .. code-tab:: csharp
  186. private string[] _fruits = { "apple", "orange", "pear", "banana" };
  187. private string _lastFruit = "";
  188. public override void _Ready()
  189. {
  190. GD.Randomize();
  191. for (int i = 0; i < 100; i++)
  192. {
  193. // Pick 100 fruits randomly.
  194. GD.Print(GetFruit());
  195. }
  196. }
  197. public string GetFruit()
  198. {
  199. string randomFruit = _fruits[GD.Randi() % _fruits.Length];
  200. while (randomFruit == _lastFruit)
  201. {
  202. // The last fruit was picked, try again until we get a different fruit.
  203. randomFruit = _fruits[GD.Randi() % _fruits.Length];
  204. }
  205. _lastFruit = randomFruit;
  206. // Returns "apple", "orange", "pear", or "banana" every time the code runs.
  207. // The function will never return the same fruit more than once in a row.
  208. return randomFruit;
  209. }
  210. This approach can be useful to make random number generation feel less
  211. repetitive. Still, it doesn't prevent results from "ping-ponging" between a
  212. limited set of values. To prevent this, use the :ref:`shuffle bag
  213. <doc_random_number_generation_shuffle_bags>` pattern instead.
  214. Get a random dictionary value
  215. -----------------------------
  216. We can apply similar logic from arrays to dictionaries as well:
  217. .. tabs::
  218. .. code-tab:: gdscript GDScript
  219. var metals = {
  220. "copper": {"quantity": 50, "price": 50},
  221. "silver": {"quantity": 20, "price": 150},
  222. "gold": {"quantity": 3, "price": 500},
  223. }
  224. func _ready():
  225. randomize()
  226. for i in range(20):
  227. print(get_metal())
  228. func get_metal():
  229. var random_metal = metals.values()[randi() % metals.size()]
  230. # Returns a random metal value dictionary every time the code runs.
  231. # The same metal may be selected multiple times in succession.
  232. return random_metal
  233. .. _doc_random_number_generation_weighted_random_probability:
  234. Weighted random probability
  235. ---------------------------
  236. The :ref:`randf() <class_@GDScript_method_randf>` method returns a
  237. floating-point number between 0.0 and 1.0. We can use this to create a
  238. "weighted" probability where different outcomes have different likelihoods:
  239. .. tabs::
  240. .. code-tab:: gdscript GDScript
  241. func _ready():
  242. randomize()
  243. for i in range(100):
  244. print(get_item_rarity())
  245. func get_item_rarity():
  246. var random_float = randf()
  247. if random_float < 0.8:
  248. # 80% chance of being returned.
  249. return "Common"
  250. elif random_float < 0.95:
  251. # 15% chance of being returned.
  252. return "Uncommon"
  253. else:
  254. # 5% chance of being returned.
  255. return "Rare"
  256. .. code-tab:: csharp
  257. public override void _Ready()
  258. {
  259. GD.Randomize();
  260. for (int i = 0; i < 100; i++)
  261. {
  262. GD.Print(GetItemRarity());
  263. }
  264. }
  265. public string GetItemRarity()
  266. {
  267. float randomFloat = GD.Randf();
  268. if (randomFloat < 0.8f)
  269. {
  270. // 80% chance of being returned.
  271. return "Common";
  272. }
  273. else if (randomFloat < 0.95f)
  274. {
  275. // 15% chance of being returned
  276. return "Uncommon";
  277. }
  278. else
  279. {
  280. // 5% chance of being returned.
  281. return "Rare";
  282. }
  283. }
  284. .. _doc_random_number_generation_shuffle_bags:
  285. "Better" randomness using shuffle bags
  286. --------------------------------------
  287. Taking the same example as above, we would like to pick fruits at random.
  288. However, relying on random number generation every time a fruit is selected can
  289. lead to a less *uniform* distribution. If the player is lucky (or unlucky), they
  290. could get the same fruit three or more times in a row.
  291. You can accomplish this using the *shuffle bag* pattern. It works by removing an
  292. element from the array after choosing it. After multiple selections, the array
  293. ends up empty. When that happens, you reinitialize it to its default value::
  294. var _fruits = ["apple", "orange", "pear", "banana"]
  295. # A copy of the fruits array so we can restore the original value into `fruits`.
  296. var _fruits_full = []
  297. func _ready():
  298. randomize()
  299. _fruits_full = _fruits.duplicate()
  300. _fruits.shuffle()
  301. for i in 100:
  302. print(get_fruit())
  303. func get_fruit():
  304. if _fruits.empty():
  305. # Fill the fruits array again and shuffle it.
  306. _fruits = _fruits_full.duplicate()
  307. _fruits.shuffle()
  308. # Get a random fruit, since we shuffled the array,
  309. # and remove it from the `_fruits` array.
  310. var random_fruit = _fruits.pop_front()
  311. # Prints "apple", "orange", "pear", or "banana" every time the code runs.
  312. return random_fruit
  313. When running the above code, there is a chance to get the same fruit twice in a
  314. row. Once we picked a fruit, it will no longer be a possible return value unless
  315. the array is now empty. When the array is empty, we reset it back to its default
  316. value, making it possible to have the same fruit again, but only once.
  317. Random noise
  318. ------------
  319. The random number generation shown above can show its limits when you need a
  320. value that *slowly* changes depending on the input. The input can be a position,
  321. time, or anything else.
  322. To achieve this, you can use random *noise* functions. Noise functions are
  323. especially popular in procedural generation to generate realistic-looking
  324. terrain. Godot provides :ref:`class_opensimplexnoise` for this, which supports
  325. 1D, 2D, 3D, and 4D noise. Here's an example with 1D noise:
  326. .. tabs::
  327. .. code-tab:: gdscript GDScript
  328. var _noise = OpenSimplexNoise.new()
  329. func _ready():
  330. randomize()
  331. # Configure the OpenSimplexNoise instance.
  332. _noise.seed = randi()
  333. _noise.octaves = 4
  334. _noise.period = 20.0
  335. _noise.persistence = 0.8
  336. for i in 100:
  337. # Prints a slowly-changing series of floating-point numbers
  338. # between -1.0 and 1.0.
  339. print(_noise.get_noise_1d(i))
  340. .. code-tab:: csharp
  341. private OpenSimplexNoise _noise = new OpenSimplexNoise();
  342. public override void _Ready()
  343. {
  344. GD.Randomize();
  345. // Configure the OpenSimplexNoise instance.
  346. _noise.Seed = (int)GD.Randi();
  347. _noise.Octaves = 4;
  348. _noise.Period = 20.0f;
  349. _noise.Persistence = 0.8f;
  350. for (int i = 0; i < 100; i++)
  351. {
  352. GD.Print(_noise.GetNoise1d(i));
  353. }
  354. }