From e386b4889ec988bc008c97f74eb4d9a075c92cc3 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 11 Aug 2023 13:54:11 -0400 Subject: [PATCH] Adding processing of world --- world.gd | 107 +++++++++++++++++++++++++++++++++++++++++++++++------ world.tscn | 34 +++++++++++++++-- 2 files changed, 126 insertions(+), 15 deletions(-) diff --git a/world.gd b/world.gd index 902730f..7d7981d 100644 --- a/world.gd +++ b/world.gd @@ -1,46 +1,129 @@ ## Conway's Game of Life -## Rules: -## 1. Any cell with >2 neighbors survives -## 2. Any dead cell with 3 live neighbors becomes alive -## 3. All other cells die (all dead cells remaing dead) +## Rule 1 - Any live cell with fewer than two live neighbours dies (underpopulation) +## Rule 2 - Any live cell with two or three live neighbours lives +## Rule 3 - Any live cell with more than three live neighbours dies (overpopulation) +## Rule 4 - Any dead cell with epos.xactly three live neighbours becomes a live cell (reproduction) extends Node2D + +enum CellStates { + DEAD, + ALIVE, +} + +@onready var generation_counter: Label = $CanvasLayer/Debug/VBoxContainer/GenerationCounter +@onready var generation_timer: Timer = $GenerationTimer +@onready var living_cells_counter: Label = $CanvasLayer/Debug/VBoxContainer/LivingCellsCounter +@onready var world_seed_label: Label = $CanvasLayer/Debug/VBoxContainer/WorldSeed + @export var world_seed: int -@export var cell_size: Vector2 = Vector2(16, 16) +@export var cell_size: Vector2 = Vector2(64, 64) @export var cell_texture: Texture2D -@export var world_size: Vector2 = Vector2(128, 128) +@export var world_size: Vector2 = Vector2(8, 8) var cell_instance var generation: int = 1 var world: Array = [] +var total_living: int = 0 + func _ready() -> void: - if world_seed: seed(world_seed) + if not world_seed: + world_seed = randi() + seed(world_seed) + world_seed_label.text = "World Seeed: %s" % world_seed + generate_world() -# Create the cell using the rendering server -func create_cell(location: Vector2) -> RID: +## Check a cell against the Conway rules +func check_cell_rules(pos: Vector2) -> void: + var neighbors := count_living_neighbors(pos) + var currently_alive = world[pos.x][pos.y] is RID + + # Rule 1 - Any live cell with fewer than two live neighbours dies (underpopulation) + if currently_alive and neighbors < 2: + kill_cell(pos) + return + # Rule 2 - Any live cell with two or three live neighbours lives + elif currently_alive and (neighbors == 2 or neighbors == 3): + total_living += 1 + return + # Rule 3 - Any live cell with more than three live neighbours dies (overpopulation) + elif currently_alive and neighbors > 3: + kill_cell(pos) + return + # Rule 4 - Any dead cell with epos.xactly three live neighbours becomes a live cell (reproduction) + elif not currently_alive and neighbors == 3: + total_living += 1 + world[pos.x][pos.y] = create_cell(pos) + return + +func count_living_neighbors(pos: Vector2) -> int: + var count := 0 + + var x_min = 0 if pos.x - 1 < 0 else pos.x - 1 + var y_min = 0 if pos.y - 1 < 0 else pos.y - 1 + var x_max = world_size.x if pos.x + 2 > world_size.x else pos.x + 2 + var y_max = world_size.y if pos.y + 2 > world_size.y else pos.y + 2 + + for x in range(x_min, x_max): + for y in range(y_min, y_max): + if x == pos.x and y == pos.y: continue # Current cell - Don't count + if world[x][y] is RID: + count += 1 + return count + +func process_generation() -> void: + generation += 1 + total_living = 0 + + for x in range(world_size.x): + for y in range(world_size.y): + check_cell_rules(Vector2(x, y)) + + + +## Create the cell using the rendering server +func create_cell(pos: Vector2) -> RID: var rs = RenderingServer + cell_instance = rs.canvas_item_create() rs.canvas_item_set_parent(cell_instance, get_canvas_item()) var rect: Rect2 = Rect2(-cell_size.x/2, -cell_size.y/2, cell_size.x, cell_size.y) # Centered with cell size rs.canvas_item_add_texture_rect(cell_instance, rect, cell_texture) - var location_fixed = Vector2(location.x * cell_size.x, location.y * cell_size.y) - var trans = Transform2D(0, location_fixed) + var pos_fixed = Vector2(pos.x * cell_size.x, pos.y * cell_size.y) + var trans = Transform2D(0, pos_fixed) rs.canvas_item_set_transform(cell_instance, trans) return cell_instance +func kill_cell(pos: Vector2) -> void: + if not world[pos.x][pos.y] is RID: return + + RenderingServer.free_rid(world[pos.x][pos.y]) + world[pos.x][pos.y] = CellStates.DEAD + + ## Generate the world with the initial cells func generate_world() -> void: for x in range(world_size.x): world.append([]) for y in range(world_size.y): if randi_range(0, 1): + total_living += 1 world[x].append(create_cell(Vector2(x, y))) else: - world[x].append(0) + world[x].append(CellStates.DEAD) + + +func _on_generation_timer_timeout() -> void: + process_generation() + + generation_counter.text = "Generation: %s" % generation + living_cells_counter.text = "Living Cells: %s" % total_living + + generation_timer.start() diff --git a/world.tscn b/world.tscn index 46ab07a..b86d53c 100644 --- a/world.tscn +++ b/world.tscn @@ -5,13 +5,41 @@ [ext_resource type="PackedScene" uid="uid://cy6vsgu8o0rad" path="res://scenes/fps_counter/fps_counter.tscn" id="3_ves6s"] [node name="World" type="Node2D"] +position = Vector2(-152, 0) script = ExtResource("1_wavft") -world_seed = 123 cell_texture = ExtResource("2_8r6bn") [node name="CanvasLayer" type="CanvasLayer" parent="."] -[node name="FPSCounter" parent="CanvasLayer" instance=ExtResource("3_ves6s")] +[node name="Debug" type="MarginContainer" parent="CanvasLayer"] +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/Debug"] +layout_mode = 2 + +[node name="FPSCounter" parent="CanvasLayer/Debug/VBoxContainer" instance=ExtResource("3_ves6s")] +layout_mode = 2 +text = "FPS: 0" + +[node name="WorldSeed" type="Label" parent="CanvasLayer/Debug/VBoxContainer"] +layout_mode = 2 +text = "World Seed: 0" + +[node name="GenerationCounter" type="Label" parent="CanvasLayer/Debug/VBoxContainer"] +layout_mode = 2 +text = "Generation: 1" + +[node name="LivingCellsCounter" type="Label" parent="CanvasLayer/Debug/VBoxContainer"] +layout_mode = 2 +text = "Living Cells: 0" [node name="Camera2D" type="Camera2D" parent="."] -position = Vector2(576, 320) +position = Vector2(464, 200) + +[node name="GenerationTimer" type="Timer" parent="."] +wait_time = 0.05 +one_shot = true +autostart = true + +[connection signal="timeout" from="GenerationTimer" to="." method="_on_generation_timer_timeout"]