conways-life

Conway's game of life in Godot4
git clone git://bsandro.tech/conways-life
Log | Files | Refs | README | LICENSE

commit c26b1c6d2c40136f51b915ddf5ca8145735f7e82
parent 9588dffe0351aadcd4243be74114cca2b95c922d
Author: bsandro <email@bsandro.tech>
Date:   Mon, 26 Aug 2024 00:07:38 +0300

obvious optimizations - only add cells once, then flip their visibility on demand

Diffstat:
M.gitignore | 1+
Aexport_presets.cfg | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mproject.godot | 2++
Mscenes/main.tscn | 2+-
Mscripts/Cell.gd | 12+++++++++++-
Mscripts/main.gd | 49++++++++++++++++++++++++-------------------------
6 files changed, 141 insertions(+), 27 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,2 +1,3 @@ # Godot 4+ specific ignores .godot/ +out/ diff --git a/export_presets.cfg b/export_presets.cfg @@ -0,0 +1,102 @@ +[preset.0] + +name="Windows Desktop" +platform="Windows Desktop" +runnable=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="out/conways-life.exe" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_wrapper=1 +binary_format/embed_pck=false +texture_format/bptc=true +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +binary_format/architecture="x86_64" +codesign/enable=false +codesign/timestamp=true +codesign/timestamp_server_url="" +codesign/digest_algorithm=1 +codesign/description="" +codesign/custom_options=PackedStringArray() +application/modify_resources=false +application/icon="" +application/console_wrapper_icon="" +application/icon_interpolation=4 +application/file_version="" +application/product_version="" +application/company_name="" +application/product_name="" +application/file_description="" +application/copyright="" +application/trademarks="" +application/export_angle=0 +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}' +$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}' +$trigger = New-ScheduledTaskTrigger -Once -At 00:00 +$settings = New-ScheduledTaskSettingsSet +$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings +Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true +Start-ScheduledTask -TaskName godot_remote_debug +while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 } +Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue" +ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue +Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue +Remove-Item -Recurse -Force '{temp_dir}'" + +[preset.1] + +name="Linux/X11" +platform="Linux/X11" +runnable=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="out/conways-life" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false + +[preset.1.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_wrapper=1 +binary_format/embed_pck=true +texture_format/bptc=true +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +binary_format/architecture="x86_64" +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="#!/usr/bin/env bash +export DISPLAY=:0 +unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" +\"{temp_dir}/{exe_name}\" {cmd_args}" +ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash +kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") +rm -rf \"{temp_dir}\"" diff --git a/project.godot b/project.godot @@ -20,6 +20,8 @@ config/icon="res://icon.svg" window/size/viewport_width=1280 window/size/viewport_height=720 +window/size/mode=2 +window/size/resizable=false window/stretch/mode="canvas_items" [rendering] diff --git a/scenes/main.tscn b/scenes/main.tscn @@ -9,6 +9,6 @@ cell_scene = ExtResource("2_tjoxl") tick_timer = NodePath("TickTimer") [node name="TickTimer" type="Timer" parent="."] -wait_time = 0.1 +wait_time = 0.3 [connection signal="timeout" from="TickTimer" to="." method="_on_tick"] diff --git a/scripts/Cell.gd b/scripts/Cell.gd @@ -2,10 +2,20 @@ class_name Cell extends Sprite2D +var is_alive:bool = false +var is_alive_next:bool = false + # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. # Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta): +func _process(_delta): pass + +func val(): + return 1 if is_alive else 0 + +func update(): + is_alive = is_alive_next + is_alive_next = false diff --git a/scripts/main.gd b/scripts/main.gd @@ -1,12 +1,11 @@ extends Node -# calculated for 1280x720 window - var field_w:int var field_h:int var cell_w:int var cell_h:int var field:Array[Array] + @export var cell_scene:PackedScene @export var tick_timer:Timer @@ -18,6 +17,7 @@ func _ready(): var cell = cell_scene.instantiate() cell.position = Vector2(0, 0) add_child(cell) + print("cell is alive:", cell.is_alive) cell_w = cell.texture.get_width() * cell.transform.get_scale().x cell_h = cell.texture.get_height() * cell.transform.get_scale().y @@ -28,10 +28,15 @@ func _ready(): print("field size: ", field_w, "x", field_h) - field.resize(field_w) + field.resize(field_h) for y in range(field_h): field[y].resize(field_w) - field[y].fill(0) + for x in range(field_w): + field[y][x] = cell_scene.instantiate() + field[y][x].position = Vector2(x*cell_w, y*cell_h) + add_child(field[y][x]) + + remove_child(cell) randomize_field() tick_timer.start() @@ -43,51 +48,45 @@ func _process(_delta): func randomize_field(): for y in range(field_h): for x in range(field_w): - field[y][x] = randi_range(0, 1) + field[y][x].is_alive_next = randi_range(0, 1) -func clear_cells(): - var children = get_children() - for child in children: - if child is Cell: - remove_child(child) +func update_field(): + for y in range(field_h): + for x in range(field_w): + field[y][x].update() func render_field(): for y in range(field_h): for x in range(field_w): - if field[y][x] == 1: - var cell = cell_scene.instantiate() - cell.position = Vector2(x*cell_w, y*cell_h) - add_child(cell) + field[y][x].visible = field[y][x].is_alive func tick_field(): - var field_new:Array[Array] = field.duplicate(true) for y in range(field_h): for x in range(field_w): - field_new[y][x] = tick_cell(x, y) - field = field_new + field[y][x].is_alive_next = tick_cell(x, y) func tick_cell(x:int, y:int): var sum:int = sum_area(x, y) - if field[y][x] == 1: # alive cell + if field[y][x].is_alive: # alive cell if sum < 3 || sum > 4: # cell dies - return 0 + return false else: # cell lives - return 1 + return true else: # dead cell if sum == 3: # cell comes alive - return 1 + return true else: # cell stays dead - return 0 + return false -func sum_area(x:int, y:int): +func sum_area(x:int, y:int): # sum 3x3 area all around the cell var cnt:int = 0; for xx in range(x-1, x+2): for yy in range(y-1, y+2): if xx>=0 && yy>=0 && xx<field_w && yy<field_h: - cnt += field[yy][xx]; + cnt += field[yy][xx].val(); return cnt func _on_tick(): - clear_cells() + update_field() render_field() tick_field()