Cellular Automata
Made with Godot 4 in GDScript. Click and drag to move, scrollwheel to zoom in/out. Most of the relevant code:
class_name Grid extends Node2D signal rule_changed(rule) # Width in cells @export_range(3, 1000) var width : int # Number of rows / generations @export_range(1, 1000) var height : int # Width of cell in pixels @export var cell_width : int # The rule number from 0 to 255 @export var rule : int : set(value): rule = value rule_changed.emit(rule) @export var scale_sensitivity := 0.03 var _grid : Array[Array] var _ruleset : Dictionary var _initial_conditions : Array[int] var _dragging := false func bin_string(n): var ret_str = "" while n > 0: ret_str = str(n & 1) + ret_str n = n >> 1 while len(ret_str) < 8: ret_str = '0' + ret_str return ret_str func _ready(): setup_ruleset() calculate_grid() func _draw(): for n in range(height): for i in range(width): var pos := Vector2(i * cell_width, n * cell_width) if _grid[n][i] == 1: var color = Color( n / float(height), i / float(width), 0 ) draw_rect(Rect2(pos, Vector2(cell_width, cell_width)), color) # Based on the rule, update ruleset dictionary func setup_ruleset(): _ruleset.clear() var rule_str = bin_string(rule) var i = len(rule_str) - 1 for b in rule_str: _ruleset[i] = int(b) i -= 1 func calculate_grid(): _grid.clear() _initial_conditions.clear() # Put a 1 in the middle of the first generation for i in range(0, width): if i == int(width / 2): _initial_conditions.append(1) else: _initial_conditions.append(0) for n in range(height): # First row, so use initial conditions if n == 0: _grid.append(_initial_conditions) else: var previous_row := _grid[n - 1] var row := [] # Apply the current rule for x in range(0, width): var value if x == 0: value = str(previous_row[width - 1]) + str(previous_row[x]) + str(previous_row[x + 1]) elif x == width - 1: value = str(previous_row[x - 1]) + str(previous_row[x]) + str(previous_row[0]) else: value = str(previous_row[x - 1]) + str(previous_row[x]) + str(previous_row[x + 1]) value = value.bin_to_int() row.append(_ruleset[value]) _grid.append(row) func update(): if is_node_ready(): setup_ruleset() calculate_grid() queue_redraw() func _on_width_input_value_changed(value): width = value update() func _on_height_input_value_changed(value): height = value update() func _on_rule_input_value_changed(value): rule = value update() func _input(event): if event is InputEventMouseButton: if event.button_index == MOUSE_BUTTON_LEFT: _dragging = event.pressed elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: scale = Vector2(scale.x - scale_sensitivity, scale.y - scale_sensitivity) elif event.button_index == MOUSE_BUTTON_WHEEL_UP: scale = Vector2(scale.x + scale_sensitivity, scale.y + scale_sensitivity) if scale.x > 4.0: scale.x = 1.0 elif scale.x <= 0.1: scale.x = 0.1 if scale.y > 4.0: scale.y = 1.0 elif scale.y <= 0.1: scale.y = 0.1 if event is InputEventMouseMotion and _dragging: position += event.relative
Status | Prototype |
Category | Other |
Platforms | HTML5 |
Author | DoodleDonut |
Made with | Godot |
Leave a comment
Log in with itch.io to leave a comment.