|
@ -39,7 +39,9 @@ var cell_instance |
|
|
var generation: int = 1 |
|
|
var generation: int = 1 |
|
|
var is_paused: int = false |
|
|
var is_paused: int = false |
|
|
var total_living: int = 0 |
|
|
var total_living: int = 0 |
|
|
var world: Array = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var cell_ids: Array = [] # Store cell RIDs |
|
|
|
|
|
var cell_states: Array = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void: |
|
|
func _ready() -> void: |
|
@ -89,11 +91,11 @@ func start_conway() -> void: |
|
|
camera.position.y = world_size.y * cell_size.y / 2 |
|
|
camera.position.y = world_size.y * cell_size.y / 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Check a cell against the Conway rules and return True if cell shoudl be alive |
|
|
|
|
|
|
|
|
## Check a cell against the Conway rules and return True if cell should be alive |
|
|
## The logic in this could be cleaned up pretty easily. Only verbose for understanding. |
|
|
## The logic in this could be cleaned up pretty easily. Only verbose for understanding. |
|
|
func cell_is_alive(pos: Vector2) -> bool: |
|
|
func cell_is_alive(pos: Vector2) -> bool: |
|
|
var neighbors := count_living_neighbors(pos) |
|
|
var neighbors := count_living_neighbors(pos) |
|
|
var currently_alive = world[pos.x][pos.y] is RID |
|
|
|
|
|
|
|
|
var currently_alive = cell_states[pos.x][pos.y] == CellStates.ALIVE |
|
|
|
|
|
|
|
|
# Rule 1 - Any live cell with fewer than two live neighbours dies (underpopulation) |
|
|
# Rule 1 - Any live cell with fewer than two live neighbours dies (underpopulation) |
|
|
if currently_alive and neighbors < 2: |
|
|
if currently_alive and neighbors < 2: |
|
@ -124,36 +126,36 @@ func count_living_neighbors(pos: Vector2) -> int: |
|
|
for x in range(x_min, x_max): |
|
|
for x in range(x_min, x_max): |
|
|
for y in range(y_min, y_max): |
|
|
for y in range(y_min, y_max): |
|
|
if x == pos.x and y == pos.y: continue # Current cell - Don't count |
|
|
if x == pos.x and y == pos.y: continue # Current cell - Don't count |
|
|
if world[x][y] is RID: |
|
|
|
|
|
|
|
|
if cell_states[x][y] == CellStates.ALIVE: |
|
|
count += 1 |
|
|
count += 1 |
|
|
return count |
|
|
return count |
|
|
|
|
|
|
|
|
## Loop through the world and create or kill cells depending on rules |
|
|
|
|
|
|
|
|
## Loop through world to generate cell states, hide/show cells depending on state |
|
|
func process_generation() -> void: |
|
|
func process_generation() -> void: |
|
|
if is_paused: return |
|
|
if is_paused: return |
|
|
|
|
|
|
|
|
generation += 1 |
|
|
generation += 1 |
|
|
total_living = 0 |
|
|
total_living = 0 |
|
|
|
|
|
|
|
|
var new_world: Array= [] |
|
|
|
|
|
|
|
|
var rs := RenderingServer |
|
|
|
|
|
|
|
|
|
|
|
var new_states: Array= [] |
|
|
for x in range(world_size.x): |
|
|
for x in range(world_size.x): |
|
|
new_world.append([]) |
|
|
|
|
|
new_world[x].resize(world_size.x) |
|
|
|
|
|
|
|
|
new_states.append([]) |
|
|
|
|
|
new_states[x].resize(world_size.x) |
|
|
for y in range(world_size.y): |
|
|
for y in range(world_size.y): |
|
|
var pos = Vector2(x, y) |
|
|
var pos = Vector2(x, y) |
|
|
if cell_is_alive(pos): |
|
|
|
|
|
total_living += 1 |
|
|
|
|
|
new_world[x][y] = create_cell(pos) |
|
|
|
|
|
else: |
|
|
|
|
|
new_world[x][y] = kill_cell(pos) |
|
|
|
|
|
|
|
|
var is_alive = cell_is_alive(pos) |
|
|
|
|
|
total_living += int(is_alive) |
|
|
|
|
|
new_states[x][y] = int(is_alive) |
|
|
|
|
|
rs.canvas_item_set_visible(cell_ids[x][y], is_alive) |
|
|
|
|
|
|
|
|
world = new_world |
|
|
|
|
|
|
|
|
cell_states = new_states |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Create the cell using the rendering server |
|
|
## Create the cell using the rendering server |
|
|
func create_cell(pos: Vector2) -> RID: |
|
|
|
|
|
if world[pos.x][pos.y] is RID: return world[pos.x][pos.y] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## This is only performed on initial world generation |
|
|
|
|
|
func create_cell(pos: Vector2, visible_cell: bool = true) -> RID: |
|
|
var rs = RenderingServer |
|
|
var rs = RenderingServer |
|
|
|
|
|
|
|
|
cell_instance = rs.canvas_item_create() |
|
|
cell_instance = rs.canvas_item_create() |
|
@ -166,26 +168,22 @@ func create_cell(pos: Vector2) -> RID: |
|
|
var trans = Transform2D(0, pos_fixed) |
|
|
var trans = Transform2D(0, pos_fixed) |
|
|
rs.canvas_item_set_transform(cell_instance, trans) |
|
|
rs.canvas_item_set_transform(cell_instance, trans) |
|
|
|
|
|
|
|
|
return cell_instance |
|
|
|
|
|
|
|
|
|
|
|
## Remove the cell from the RenderingServer, if it exists |
|
|
|
|
|
func kill_cell(pos: Vector2) -> CellStates: |
|
|
|
|
|
if world[pos.x][pos.y] is RID: |
|
|
|
|
|
RenderingServer.free_rid(world[pos.x][pos.y]) |
|
|
|
|
|
return CellStates.DEAD |
|
|
|
|
|
|
|
|
rs.canvas_item_set_visible(cell_instance, visible_cell) |
|
|
|
|
|
|
|
|
|
|
|
return cell_instance |
|
|
|
|
|
|
|
|
## Generate the world with cells in random states (alive or dead) |
|
|
## Generate the world with cells in random states (alive or dead) |
|
|
func generate_world() -> void: |
|
|
func generate_world() -> void: |
|
|
for x in range(world_size.x): |
|
|
for x in range(world_size.x): |
|
|
world.append([]) |
|
|
|
|
|
world[x].resize(world_size.x) |
|
|
|
|
|
|
|
|
cell_ids.append([]) |
|
|
|
|
|
cell_ids[x].resize(world_size.x) |
|
|
|
|
|
cell_states.append([]) |
|
|
|
|
|
cell_states[x].resize(world_size.x) |
|
|
for y in range(world_size.y): |
|
|
for y in range(world_size.y): |
|
|
if randi_range(0, 1): |
|
|
|
|
|
total_living += 1 |
|
|
|
|
|
world[x][y] = create_cell(Vector2(x, y)) |
|
|
|
|
|
else: |
|
|
|
|
|
world[x][y] = CellStates.DEAD |
|
|
|
|
|
|
|
|
var is_alive: int = randi_range(0, 1) |
|
|
|
|
|
total_living += is_alive |
|
|
|
|
|
cell_states[x][y] = is_alive |
|
|
|
|
|
cell_ids[x][y] = create_cell(Vector2(x, y), bool(is_alive)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _on_generation_timer_timeout() -> void: |
|
|
func _on_generation_timer_timeout() -> void: |
|
|