Skip to content

Instantly share code, notes, and snippets.

@CowThing
Last active March 6, 2021 23:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CowThing/5b4be448bffd1d6a8836d48408e47d27 to your computer and use it in GitHub Desktop.
Save CowThing/5b4be448bffd1d6a8836d48408e47d27 to your computer and use it in GitHub Desktop.
Random number generator class for Godot 3.2
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