Random Library
A helper library for various randomisation functions.
Intro
A simple collection of utility functions, wrapped up in a class and rewritten for Godot 4.
It gives me easy access to repeatable random things - eg. lets me save the seed so that procedural generation can proceed to generate the same things the next time the player loads that level etc.
(And it’s also a lot more convenient to type something like instance.get_color()
to get a random color, or especially instance.from_vector2(first, second)
to get a random vector between two bounds.)
The Library
class_name Random
"""
interface to provide easy access to repeatable RNG helper functions
"""
var rng : RandomNumberGenerator :
set (_rng):
rng = _rng
get:
if not rng:
rng = RandomNumberGenerator.new()
return rng
func set_seed(_rseed : int = 0) -> void:
rng.set_seed(_rseed) if _rseed != 0 else rng.randomize()
func get_seed() -> int:
return rng.seed
### fundamental
func get_int(from : int = 0, to : int = 100) -> int:
return rng.randi_range(from, to)
func get_float(from : float = 0.0, to : float = 1.0, can_invert : bool = false) -> float:
var value = rng.randf_range(from, to)
if can_invert and get_float() > 0.5:
value = -value
return value
### colors
func get_color() -> Color:
return Color(get_float(), get_float(), get_float())
func get_color_on_gradient(gradient : Gradient) -> Color:
return gradient.sample(get_float())
### dice / coin
func roll(n : int = 3, sides : int = 6) -> int:
return range(n).reduce(func(total, _idx): return total + get_int(1, sides), 0)
func toss_coin() -> bool:
return (get_int() < 50)
### vectors
func from_vector2(from : Vector2 = Vector2.ZERO, to : Vector2 = Vector2.ONE) -> Vector2:
return Vector2(get_float(from.x, to.x), get_float(from.y, to.y))
func from_vector2i(from : Vector2i = Vector2i.ZERO, to : Vector2i = Vector2i.ONE) -> Vector2i:
return Vector2i(get_int(from.x, to.x), get_int(from.y, to.y))
func from_vector3(from : Vector3 = Vector3.ZERO, to : Vector3 = Vector3.ONE) -> Vector3:
return Vector3(get_float(from.x, to.x), get_float(from.y, to.y), get_float(from.z, to.z))
func from_vector3i(from : Vector3i = Vector3i.ZERO, to : Vector3i = Vector3i.ONE) -> Vector3i:
return Vector3i(get_int(from.x, to.x), get_int(from.y, to.y), get_int(from.z, to.z))
# flip the arguments as it's often more useful to generate from 0->x and godot isn't capable of passing named arguments
func to_vector2(to : Vector2 = Vector2.ONE, from : Vector2 = Vector2.ZERO) -> Vector2:
return from_vector2(from, to)
func to_vector2i(to : Vector2i = Vector2i.ONE, from : Vector2i = Vector2i.ZERO) -> Vector2i:
return from_vector2i(from, to)
func to_vector3(to : Vector3 = Vector3.ONE, from : Vector3 = Vector3.ZERO) -> Vector3:
return from_vector3(from, to)
func to_vector3i(to : Vector3i = Vector3i.ONE, from : Vector3i = Vector3i.ZERO) -> Vector3i:
return from_vector3i(from, to)
### arrays / dicts
func from_array(_array : Array):
var idx = get_int(0, _array.size()-1)
return _array[idx]
func from_dictionary(_dict : Dictionary):
var idx = get_int(0, _dict.keys().size()-1)
return _dict[_dict.keys()[idx]]
Test Script
And a quick test script to demonstrate - attach it any Node and check the console:
extends Node
var array = [1,2,"apple",4,5,"fish",7,8,9,"banana"]
func _ready() -> void:
var test1 = Random.new()
var test2 = Random.new()
test1.set_seed(123)
test_array("a", test1, 5)
print("globally called random in the middle = %s\n" % randf())
test_array("b", test1, 5)
test2.set_seed(42)
test_array("c", test2, 10)
test1.set_seed(123)
test_array("d", test1, 5)
print("globally called random in the middle = %s\n" % randf())
test2.set_seed(42)
test_array("e", test2, 10)
test_array("f", test1, 5)
func test_array(id : String, rng : Random, length : int = 3):
print("--- test (%s) seed = %s ---" % [id, rng.get_seed()])
var test = range(0, length).reduce(func(out, _idx): return "%s %s" % [out, rng.from_array(array)], "")
print(test+"\n")
Running that test gives me output of:
--- test (a) seed = 123 ---
5 banana 1 fish fish
globally called random in the middle = 0.8317563533783
--- test (b) seed = 123 ---
5 5 banana 4 apple
--- test (c) seed = 42 ---
8 9 1 fish apple 7 9 4 banana 2
--- test (d) seed = 123 ---
5 banana 1 fish fish
globally called random in the middle = 0.49645981192589
--- test (e) seed = 42 ---
8 9 1 fish apple 7 9 4 banana 2
--- test (f) seed = 123 ---
5 5 banana 4 apple
Note that your own test output will be different from mine, but all your (a
+d
), (c
+e
) and (b
+f
) pairs should match.