Skip to content

Add classes for random number generation (RNG)

Created by: lmbarros

This is perhaps more a request for comments than a real pull request. I still have some doubts about how to do things the Godot way (see my questions below), but overall this is the design I'd personally like to see in the engine.

It is used like this:

var rng = RandPCG32.new()   # Or another RNG class, like Xoroshiro128Plus
rng.seed(1234)  # rng.randomize() also exists

n = rng.uniform_float(-1.0, 2.0) # uniform in interval [-1.0, 2.0]
n = rng.uniform_int(1, 6) # six-sided die
n = rng.boolean(0.1)  # 10% of chance of being true
n = rng.normal(-3.0, 2.0)  # Gaussian, mean = -3, std. deviation = 2.0
n = rng.exponential(2.0) # from exponential distribution with mean = 2.0

I believe the current random number generation facilities in Godot are good for simple use cases (and I'd say that they should remain available), but more "interesting" RNG usage needs something new. I had three main goals in mind:

  1. Add a few more useful distributions beyond uniform.

  2. Let the user create separate instances of the RNG algorithm, in order to generate different independent sequences (pretty useful for procedural generation of content).

  3. Allow users to be sure that they can create reproducible pseudorandom sequences even between Godot releases.

The biggest open points and questions I still have are:

  • Do you consider this design in general good for Godot?
    • One sub-question here: What about providing multiple RNG algorithms as I did? I think that choosing a RNG is a trade-off, so I like the idea of providing the alternatives and letting the user chose one. Providing one single Rand class would be simpler (which is good), but if we ever decide to replace the one algorithm with something else, my point 3 above is not achieved. And I like RNG algorithms, so my opinion is biassed :-)
  • How to add tests for this? I am currently using a Godot project (https://github.com/lmbarros/GodotRandTest/ -- it is currently quite ugly, BTW) that calls my methods from GDScript and checks if the results are OK. However, in order to be able to make these tests, I was required to expose Rand::random() to GDScript, which otherwise I wouldn't.
  • Sometimes it is useful to save the RNG state with a saved game (to avoid the save-reload-and-try-again "cheat"). I am a Godot beginner, so I don't know if there is any support or standard way for doing serialization or save games.
  • The newer versions of the C++ standard have implementations of various RNG algorithms and random distributions. For some reason that beyond my own understanding I haven't used them here. Is the usage of these newer parts of the C++ standard library allowed or encouraged in Godot?
  • I implemented this on Linux and didn't test anywhere else. There is nothing platform-specific here, but we may need to tweak the implementation a bit to make it compile everywhere.

Six RNG algorithms are provided: PCG32, Xoroshiro128+, two variations of Mersenne Twister (MT19937 and MT19937-64), SplitMix64 and a simple LCG. Different random distributions are provided: uniform (for integers and floats), normal (Gaussian), exponential and Bernoulli (for generating Booleans).

All algorithms and distributions are usable from GDScript.

The base Rand class contains the interface that must be implemented by all RNG algorithms and the implementation of the different distributions. Subclasses that implement each of the actual RNG algorithms inherit the distributions. This way, new algorithms and new distributions can be easily added, and every algorithm can be used with every distribution.

Merge request reports