Last active
November 5, 2024 13:34
-
-
Save CowThing/5b4be448bffd1d6a8836d48408e47d27 to your computer and use it in GitHub Desktop.
Random number generator class for Godot 3.2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends Reference | |
class_name Random | |
""" | |
A self contained random number generator class. Use this for non-global random number generation. | |
Create the class using `Random.new()`, optionally input a seed directly while creating. | |
Notes | |
---- | |
You only need to call `randomize_seed()` once to make the seed random. | |
Restoring the random state with `restore_state()` allows you to replay the random numbers in | |
order since the last time `save_state()` was called. | |
""" | |
const RAND_MAX : = float(0xFFFFFFFF) | |
var current_seed = 0 setget set_seed | |
var _current_state : int = 0 | |
var _saved_state : int = 0 | |
func _init(input_seed = 0) -> void: | |
set_seed(input_seed) | |
func set_seed(input) -> void: | |
# Set the seed. If the input is a string it will be converted to a number. | |
var new_seed : = 0 | |
match typeof(input): | |
TYPE_INT, TYPE_REAL: | |
new_seed = input | |
TYPE_STRING: | |
if input.is_valid_integer(): | |
new_seed = input.to_int() | |
elif input.is_valid_float(): | |
new_seed = input.to_float() | |
else: | |
new_seed = hash(input) | |
current_seed = new_seed | |
_current_state = current_seed | |
save_state() | |
func randomize_seed() -> void: | |
set_seed(OS.get_ticks_usec() * 6580885991 + 285005408160) | |
func rand_int() -> int: | |
var r : = rand_seed(_current_state) | |
_current_state = r[1] | |
# The random value returned from rand_seed range from -2^31 to 2^31 | |
# Adding 2^31 makes the value range from 0 to 2^32 | |
return int(r[0] + 0x80000000) | |
func rand_float() -> float: | |
return rand_int() / RAND_MAX | |
func rand_range_int(lower : int, upper : int) -> int: | |
if upper <= lower: | |
return lower | |
var range_value : int = upper - lower | |
return lower + rand_int() % range_value | |
func rand_range_float(lower : float, upper : float) -> float: | |
if upper <= lower: | |
return lower | |
var range_value : float = upper - lower | |
return lower + rand_float() * range_value | |
func rand_vector2(lower : float, upper : float) -> Vector2: | |
return Vector2( | |
rand_range_float(lower, upper), | |
rand_range_float(lower, upper) | |
) | |
func rand_vector3(lower : float, upper : float) -> Vector3: | |
return Vector3( | |
rand_range_float(lower, upper), | |
rand_range_float(lower, upper), | |
rand_range_float(lower, upper) | |
) | |
func rand_direction2() -> Vector2: | |
# Returns a random normalized Vector2 | |
var a : = rand_float() * TAU | |
return Vector2(cos(a), sin(a)) | |
func rand_direction3() -> Vector3: | |
# Returns a random normalized Vector3 | |
var a : = rand_float() * TAU | |
var b : = acos(rand_float() * 2.0 - 1.0) | |
return Vector3(sin(b) * cos(a), sin(b) * sin(a), cos(b)) | |
func rand_roll_int(lower : int, upper : int, clump : int) -> int: | |
# Retruns a random integer within a given range that clumps towards the middle based on the clump factor. | |
if upper <= lower: | |
return lower | |
if clump <= 1: | |
return rand_range_int(lower, upper) | |
var range_value : int = upper - lower | |
var total : = 0.0 | |
var factor : = 1.0 / clump | |
for i in clump: | |
total += rand_float() * range_value * factor | |
return lower + int(total) | |
func rand_roll_float(lower : float, upper : float, clump : int) -> float: | |
# Retruns a random float within a given range that clumps towards the middle based on the clump factor. | |
if upper <= lower: | |
return lower | |
if clump <= 1: | |
return rand_range_float(lower, upper) | |
var range_value : float = upper - lower | |
var total : = 0.0 | |
var factor : = 1.0 / clump | |
for i in clump: | |
total += rand_float() * range_value * factor | |
return lower + total | |
func rand_bool(percentage : float) -> bool: | |
# Percentage from 0.0 to 1.0 | |
return rand_int() < RAND_MAX * clamp(percentage, 0.0, 1.0) | |
func rand_normal(mean : = 0.0, deviation : = 1.0) -> float: | |
return mean + deviation * cos(TAU * rand_float()) * sqrt(-2.0 * log(rand_float())) | |
func rand_weighted(dictionary : Dictionary): | |
# All values in the dictionary must be numbers. | |
# Returns a random key from the dictionary based on the value weights. | |
var sum_of_weights : = 0.0 | |
for key in dictionary: | |
sum_of_weights += dictionary[key] | |
var x : = rand_float() * sum_of_weights | |
var cumulative_weight : = 0.0 | |
for key in dictionary: | |
cumulative_weight += dictionary[key] | |
if x < cumulative_weight: | |
return key | |
func shuffle_array(array : Array) -> void: | |
var size : int = array.size() | |
if size < 2: | |
return | |
for i in range(size - 1, 0, -1): | |
var j : int = rand_int() % (i + 1) | |
var temp = array[j] | |
array[j] = array[i] | |
array[i] = temp | |
func save_state() -> void: | |
_saved_state = _current_state | |
func restore_state() -> void: | |
_current_state = _saved_state |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment