197 lines
4.0 KiB
GDScript
197 lines
4.0 KiB
GDScript
extends Sprite2D
|
|
|
|
var n: int = 64
|
|
var arr := []
|
|
|
|
var data_img: Image
|
|
var data_tex: ImageTexture
|
|
|
|
var gol := GoL.new()
|
|
|
|
@onready var mat: ShaderMaterial = material as ShaderMaterial
|
|
|
|
# sim. consts
|
|
var T := 0.01
|
|
var t := 0.0
|
|
|
|
# player (2x2 block)
|
|
var player_alive := true
|
|
var player_col := 10
|
|
var player_row := 10
|
|
var PLAYER_SHAPE := [Vector2i(0,0), Vector2i(1,0), Vector2i(0,1), Vector2i(1,1)]
|
|
|
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
func _ready() -> void:
|
|
data_img = Image.create(n, n, false, Image.FORMAT_R8)
|
|
data_img.fill(Color8(0, 0, 0, 255))
|
|
|
|
data_tex = ImageTexture.create_from_image(data_img)
|
|
mat.set_shader_parameter("binDataTex", data_tex)
|
|
mat.set_shader_parameter("n", n)
|
|
|
|
# player
|
|
_seed_clear()
|
|
_fill_example()
|
|
_spawn_player(20, 10)
|
|
_upload_arr()
|
|
|
|
|
|
func _upload_arr() -> void:
|
|
for y in n:
|
|
for x in n:
|
|
var v := int(arr[y][x]) * 255
|
|
data_img.set_pixel(x, y, Color8(v, 0, 0, 255))
|
|
data_tex.update(data_img)
|
|
|
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
func _process(_delta: float) -> void:
|
|
if Input.is_action_just_pressed("move_right"):
|
|
_move_player(1, 0)
|
|
if Input.is_action_just_pressed("move_left"):
|
|
_move_player(-1, 0)
|
|
if Input.is_action_just_pressed("move_up"):
|
|
_move_player(0, -1)
|
|
if Input.is_action_just_pressed("move_down"):
|
|
_move_player(0, 1)
|
|
|
|
t += _delta
|
|
if t >= T:
|
|
t = 0.0
|
|
_game_of_life_step()
|
|
# arr = gol.step_once(arr, n) # cpp step (no player)
|
|
_track_player_after_step()
|
|
_upload_arr()
|
|
|
|
func _game_of_life_step() -> void:
|
|
var next := []
|
|
for y in n:
|
|
var row := []
|
|
for x in n:
|
|
var alive: bool = arr[y][x] == 1
|
|
var cn := _count_neighs(x, y)
|
|
|
|
var newv := 0
|
|
if alive:
|
|
newv = int(cn == 2 or cn == 3)
|
|
else:
|
|
newv = int(cn == 3)
|
|
row.append(newv)
|
|
next.append(row)
|
|
arr = next
|
|
|
|
func _count_neighs(x:int, y:int) -> int:
|
|
var ans := 0
|
|
for _dy in 3:
|
|
var dy := _dy-1
|
|
for _dx in 3:
|
|
var dx := _dx-1
|
|
if dx == 0 and dy == 0:
|
|
continue
|
|
var nx := int((x + dx + n)%n)
|
|
var ny := int((y + dy + n)%n)
|
|
ans += arr[ny][nx]
|
|
return ans
|
|
|
|
|
|
func _track_player_after_step() -> void:
|
|
if not player_alive:
|
|
return
|
|
var best_count := -1
|
|
var best_shift := Vector2i(0, 0)
|
|
|
|
# search a 5x5 neighborhood for where the 2x2 footprint moved
|
|
for dy in range(-2, 3):
|
|
for dx in range(-2, 3):
|
|
var cnt := 0
|
|
for off in PLAYER_SHAPE:
|
|
var x:int = (player_col + off.x + dx + n) % n
|
|
var y:int = (player_row + off.y + dy + n) % n
|
|
cnt += arr[y][x]
|
|
if cnt > best_count:
|
|
best_count = cnt
|
|
best_shift = Vector2i(dx, dy)
|
|
|
|
# if nothing from the footprint survived, the player is dead
|
|
if best_count <= 0:
|
|
player_alive = false
|
|
print("Player dead!")
|
|
return
|
|
|
|
player_col = (player_col + best_shift.x + n) % n
|
|
player_row = (player_row + best_shift.y + n) % n
|
|
|
|
|
|
func _fill_example() -> void:
|
|
#_checkerboard()
|
|
_ship()
|
|
|
|
# inits
|
|
func _checkerboard() -> void:
|
|
for y in n:
|
|
var row := []
|
|
for x in n:
|
|
row.append((x + y) % 2) # checkerboard
|
|
arr.append(row)
|
|
|
|
func _ship() -> void:
|
|
var i: int = 0
|
|
var j: int = 0
|
|
while (i < n):
|
|
var row := []
|
|
j = 0
|
|
while (j < n):
|
|
row.append(0)
|
|
j+=1
|
|
arr.append(row)
|
|
i+=1
|
|
|
|
arr[0][1] = 1
|
|
arr[1][2] = 1
|
|
arr[2][0] = 1
|
|
arr[2][1] = 1
|
|
arr[2][2] = 1
|
|
|
|
|
|
# Player
|
|
func _write_player(val:int) -> void:
|
|
for off in PLAYER_SHAPE:
|
|
var x:int = (player_col + off.x + n) % n
|
|
var y:int = (player_row + off.y + n) % n
|
|
arr[y][x] = val
|
|
|
|
func _spawn_player(col:int, row:int) -> void:
|
|
player_col = (col + n) % n
|
|
player_row = (row + n) % n
|
|
player_alive = true
|
|
_write_player(1)
|
|
_upload_arr()
|
|
|
|
func _despawn_player() -> void:
|
|
if player_alive:
|
|
_write_player(0)
|
|
player_alive = false
|
|
_upload_arr()
|
|
|
|
func _move_player(dx:int, dy:int) -> void:
|
|
if not player_alive:
|
|
return
|
|
# erase old footprint
|
|
_write_player(0)
|
|
# move
|
|
player_col = (player_col + dx + n) % n
|
|
player_row = (player_row + dy + n) % n
|
|
# write new footprint
|
|
_write_player(1)
|
|
_upload_arr()
|
|
|
|
|
|
# Clear
|
|
func _seed_clear() -> void:
|
|
arr.clear()
|
|
for _y in n:
|
|
var row := []
|
|
for _x in n:
|
|
row.append(0)
|
|
arr.append(row)
|