Compare commits

...

6 commits

16 changed files with 131 additions and 113 deletions

View file

@ -2,6 +2,8 @@ extends TextureRect
@export var colors : Array[Color] = [Color(0.3, 1, 1) * 0.7, Color(1, 0.6, 0.6) * 0.7, Color(1, 1, 1) * 0.7] @export var colors : Array[Color] = [Color(0.3, 1, 1) * 0.7, Color(1, 0.6, 0.6) * 0.7, Color(1, 1, 1) * 0.7]
# Modulate the background with an interpolation of the colors in the list,
# depending on the players position on the earth.
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
var index : int = floor((%Player.position.angle() + PI)/ TAU * colors.size()) var index : int = floor((%Player.position.angle() + PI)/ TAU * colors.size())
var diff = (%Player.position.angle() + PI)/ TAU * colors.size() - index var diff = (%Player.position.angle() + PI)/ TAU * colors.size() - index

View file

@ -15,31 +15,9 @@ func _ready() -> void:
if blocks_area: if blocks_area:
Grid.buildings.append(self) Grid.buildings.append(self)
await get_tree().create_timer(0.2).timeout
if get_node_or_null("ObjectList") != null: if get_node_or_null("ObjectList") != null:
var obj_list = $ObjectList var obj_list = $ObjectList
obj_list.reparent(get_tree().get_root().get_node("main"), false) Grid.call_deferred("place_object_list", obj_list, self)
await get_tree().create_timer(0.2).timeout
var objects_to_be_placed = obj_list.get_children()
for object in objects_to_be_placed:
var offset = object.global_position;
object.global_position = Grid.get_world_position(location, offset)
# The building remembers these objects: If it is destroyed, so are they.
if object is Platform or object is Trap or object is Item:
objects.append(object)
if "building" in object: object.building = self
# This scales platforms hoizontally to make sure they still form a floor without gaps.
if(object.has_method("init_at_horizontal_distortion")):
object.init_at_horizontal_distortion(object.position.length() / Grid.ground_radius)
grid_entrance_callback(object)
func grid_entrance_callback(object : Node):
# Objects receive a callback when placed, starting from the deepest children
for child in object.get_children():
grid_entrance_callback(child)
if object.has_method("_enter_grid"):
object.call_deferred("_enter_grid")
func overlaps(other : Building): func overlaps(other : Building):
# heights don't overlap # heights don't overlap

View file

@ -102,7 +102,7 @@ func destroy_below():
func wave(): func wave():
# Raise a wave from the water at the boundary of the screen and move it towards the center. # Raise a wave from the water at the boundary of the screen and move it towards the center.
var angle = player.position.angle var angle = player.position.angle()
var dir = randi_range(0, 1) * 2 - 1 var dir = randi_range(0, 1) * 2 - 1
var speed = 3000 / water.radius_base var speed = 3000 / water.radius_base
water.create_tsunami(angle - speed * dir * TAU/30, dir, speed) water.create_tsunami(angle - speed * dir * TAU/30, dir, speed)

View file

@ -14,7 +14,7 @@
[ext_resource type="Script" uid="uid://cpaskpj67pnaj" path="res://enemies/boss/boss_spawner.gd" id="10_efxa6"] [ext_resource type="Script" uid="uid://cpaskpj67pnaj" path="res://enemies/boss/boss_spawner.gd" id="10_efxa6"]
[ext_resource type="PackedScene" uid="uid://cqn67nwyrtq3k" path="res://ui/journal/journal.tscn" id="10_w48qg"] [ext_resource type="PackedScene" uid="uid://cqn67nwyrtq3k" path="res://ui/journal/journal.tscn" id="10_w48qg"]
[ext_resource type="PackedScene" uid="uid://cpe4s6vsn0ujd" path="res://enemies/boss/boss.tscn" id="11_efxa6"] [ext_resource type="PackedScene" uid="uid://cpe4s6vsn0ujd" path="res://enemies/boss/boss.tscn" id="11_efxa6"]
[ext_resource type="Script" uid="uid://gul4u5tw1vxk" path="res://bg_image.gd" id="13_vivmo"] [ext_resource type="Script" uid="uid://gul4u5tw1vxk" path="res://background/bg_image.gd" id="13_vivmo"]
[node name="main" type="Node2D"] [node name="main" type="Node2D"]

View file

@ -1,20 +1,24 @@
extends Control extends Control
@onready var item_list : ItemList = $ItemList @onready var item_list : ItemList = $ItemList
var item_list_no_dupes = []
# Add items from each pool to journal. TODO: Deal with multiplicities. # Add items from each pool to journal.
func _ready() -> void: func _ready() -> void:
await get_tree().create_timer(0.3).timeout
for item_scene in ItemSpawn.item_pool.common: for item_scene in ItemSpawn.item_pool.common:
add_item_to_journal(item_scene.instantiate()) add_item_to_journal(item_scene)
for item_scene in ItemSpawn.item_pool.rare: for item_scene in ItemSpawn.item_pool.rare:
add_item_to_journal(item_scene.instantiate()) add_item_to_journal(item_scene)
for item_scene in ItemSpawn.item_pool.unique: for item_scene in ItemSpawn.item_pool.unique:
add_item_to_journal(item_scene.instantiate()) add_item_to_journal(item_scene)
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
if Input.is_action_just_pressed("journal"): if Input.is_action_just_pressed("journal"):
visible = not visible visible = not visible
func add_item_to_journal(item: Item): # Adds an item to the journal if it was not yet added
item_list.add_item(item.item_name, item.icon) func add_item_to_journal(item_scene):
if not item_list_no_dupes.has(item_scene):
item_list_no_dupes.append(item_scene)
var item = item_scene.instantiate()
item_list.add_item(item.item_name, item.icon)

View file

@ -1,40 +1,37 @@
class_name VineNode extends Node2D class_name GridNode extends Node2D
@export var vine : Vine # Setting location and offset automatically adjusts position
@export var location : Vector2 : @export var location : Vector2 :
set(new_loc): set(new_loc):
location = Global.vec_mod(new_loc, Grid.num_collumns, true) location = Global.vec_mod(new_loc, Grid.num_collumns, true)
@export var offset : Vector2 update_position()
@export var offset : Vector2 :
set(new_offset):
offset = new_offset
update_position()
@export var depth : int @export var depth : int
func _get(property: StringName) -> Variant: # Setting the global position automatically adjusts location and offset
if property == "position":
update_position()
return position
if property == "global_position":
update_position()
return global_position
return null
func _set(property: StringName, value: Variant) -> bool: func _set(property: StringName, value: Variant) -> bool:
if property == "global_position": if property == "global_position":
location = Grid.get_location_from_world_pos(value) location = Grid.get_location_from_world_pos(value)
offset = Grid.get_offset_from_world_pos(value) offset = Grid.get_offset_from_world_pos(value)
update_position() update_position()
return true return true
if property == "position":
update_position()
return false
return false return false
# Generates position from location and offset
func update_position(): func update_position():
global_position = Grid.get_world_position(location, offset) global_position = Grid.get_world_position(location, offset)
func _enter_grid() -> void: func _enter_grid() -> void:
update_position() update_position()
func _init(_vine = null, _location = Vector2.ZERO, _offset = Vector2.ZERO, _depth = 0): # Constructor for Grid Nodes
vine = _vine func _init(_location = Vector2.ZERO, _offset = Vector2.ZERO):
location = _location location = _location
offset = _offset offset = _offset
depth = _depth
static func random_at(_location):
var rand_offset = Vector2(randf_range(60, 240), randf_range(90, 270))
return GridNode.new(_location, rand_offset)

View file

@ -1,14 +1,18 @@
class_name Bud extends VineNode class_name Bud extends GridNode
signal opened signal opened
var img_path var img_path
@export var vine : Vine
# Triggers when a bud is hit. Spreads the vine, then removes the bud # Triggers when a bud is hit. Spreads the vine, then removes the bud
func _on_opened(): func _on_opened():
$EnemyHurtbox.monitorable = false
$EnemyHurtbox.monitoring = false
$AnimatedSprite2D.play("open") $AnimatedSprite2D.play("open")
opened.emit() opened.emit()
spread() spread()
await $AnimatedSprite2D.animation_finished await $AnimatedSprite2D.animation_finished
queue_free() for child in get_children():
queue_free()
# Spread in all directions where the given vine is not yet present # Spread in all directions where the given vine is not yet present
func spread(): func spread():
@ -19,5 +23,5 @@ func spread():
# Grow a vine # Grow a vine
func grow_to_next_bud(dir): func grow_to_next_bud(dir):
var target_location = Global.vec_mod(location + dir, Grid.num_collumns, true) var target_location = Global.vec_mod(location + dir, Grid.num_collumns, true)
var target = vine.random_vine_node_at(target_location) var target = GridNode.random_at(target_location)
await vine.grow_vine_sequence(self, target, true, false) await vine.grow_vine_sequence(self, target, true, false)

View file

@ -1,4 +1,5 @@
class_name Petal extends VineNode class_name Petal extends GridNode
@export var vine : Vine
@export var vine_resource : PackedScene @export var vine_resource : PackedScene
var activated = false var activated = false

View file

@ -44,7 +44,7 @@ var vine_end_data = []
func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int): func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int):
var sprite = Sprite2D.new() var sprite = Sprite2D.new()
get_tree().get_root().get_node("main").add_child(sprite) get_tree().get_root().get_node("main").add_child(sprite)
if active_depth >= depth: if active_depth >= depth or fully_active:
sprite.texture = ResourceLoader.load(img_path_active) sprite.texture = ResourceLoader.load(img_path_active)
else: else:
sprite.texture = ResourceLoader.load(img_path_inactive) sprite.texture = ResourceLoader.load(img_path_inactive)
@ -59,7 +59,7 @@ func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int):
sprite.z_index = -1 sprite.z_index = -1
# Grows a sequence of vine segments from grid position 1 to grid position 2, starting at given depth. # Grows a sequence of vine segments from grid position 1 to grid position 2, starting at given depth.
func grow_vine_sequence(start : VineNode, target: VineNode, grow_bud = false, quick_spawn = false): func grow_vine_sequence(start : GridNode, target: GridNode, grow_bud = false, quick_spawn = false):
var depth = min(start.depth, max_depth) var depth = min(start.depth, max_depth)
# Calculate the number and length of segments from the distance of source and target # Calculate the number and length of segments from the distance of source and target
@ -86,21 +86,29 @@ func grow_vine_sequence(start : VineNode, target: VineNode, grow_bud = false, qu
if not quick_spawn: if not quick_spawn:
await get_tree().create_timer(0.2).timeout await get_tree().create_timer(0.2).timeout
if active_depth >= depth + num_segments: # If growing while active, place buds
if active_depth >= depth + num_segments or fully_active:
if grow_bud and target.location.y > 0 and target.location.y <= Grid.max_bud_height: if grow_bud and target.location.y > 0 and target.location.y <= Grid.max_bud_height:
spawn_bud(target.location, target.offset, depth + num_segments) spawn_bud(target.location, target.offset, depth + num_segments)
else: else:
# Otherwise, remember the spot to spawn a bud later.
# Further, note that the previous location is no longer a leaf unless it is the petal.
if target.location.y > 0 and target.location.y <= Grid.max_bud_height: if target.location.y > 0 and target.location.y <= Grid.max_bud_height:
for i in range(vine_end_data.size()): for i in range(vine_end_data.size()):
if vine_end_data[i].location == start.location: if vine_end_data[i].location == start.location and not vine_end_data[i] is Petal:
vine_end_data.remove_at(i) vine_end_data.remove_at(i)
break break
target.depth = depth + num_segments target.depth = depth + num_segments
vine_end_data.append(target) vine_end_data.append(target)
# Register the new vine segment in the grid
Grid.add_vine_to(self, target.location) Grid.add_vine_to(self, target.location)
vine_locations.append(Global.vec_mod(target.location, Grid.num_collumns, true)) vine_locations.append(Global.vec_mod(target.location, Grid.num_collumns, true))
# Generates a random function on (segment_count - 1)
# many grid points with bounded second derivative
func generate_random_offsets(segment_count, max_second_derivative): func generate_random_offsets(segment_count, max_second_derivative):
# First, randomize the derivative of the desired function
var differences = [] var differences = []
var last_diff = 0 var last_diff = 0
for i in range(segment_count): for i in range(segment_count):
@ -108,11 +116,15 @@ func generate_random_offsets(segment_count, max_second_derivative):
differences.append(new_diff) differences.append(new_diff)
last_diff = new_diff last_diff = new_diff
var sum = 0.0 var sum = 0.0
# Shift that derivative by a constant to add up to 0
for i in range(segment_count): for i in range(segment_count):
sum += differences[i] sum += differences[i]
var correction = - sum / segment_count var correction = - sum / segment_count
for i in range(segment_count): for i in range(segment_count):
differences[i] += correction differences[i] += correction
# Return the partial sums over the derivative constructed above
var ret = [] var ret = []
var next_val = 0 var next_val = 0
for i in range(segment_count): for i in range(segment_count):
@ -120,6 +132,7 @@ func generate_random_offsets(segment_count, max_second_derivative):
next_val += differences[i] next_val += differences[i]
return ret return ret
# Instantiates a bud
func spawn_bud(location, offset, depth): func spawn_bud(location, offset, depth):
var bud = bud_resource.instantiate() var bud = bud_resource.instantiate()
bud.location = location bud.location = location
@ -128,9 +141,13 @@ func spawn_bud(location, offset, depth):
bud.depth = depth bud.depth = depth
get_tree().get_root().get_node("main").add_child(bud) get_tree().get_root().get_node("main").add_child(bud)
# Upon activation start the process of slowly increasing the active depth
func activate(): func activate():
update_active_depth() if active_depth < 0:
update_active_depth()
# Progressively activate the vine by retexturing its sprites and spawning buds if neccessary
# Once max_depth is reached, fully activate the vine
func update_active_depth(): func update_active_depth():
if active_depth < max_depth: if active_depth < max_depth:
await get_tree().create_timer(0.15).timeout await get_tree().create_timer(0.15).timeout
@ -138,11 +155,13 @@ func update_active_depth():
if vine_data.size() > active_depth: if vine_data.size() > active_depth:
for sprite in vine_data[active_depth]: for sprite in vine_data[active_depth]:
sprite.texture = ResourceLoader.load(img_path_active) sprite.texture = ResourceLoader.load(img_path_active)
for data in vine_end_data: for node in vine_end_data:
if data.depth == active_depth: if node.depth == active_depth and not node is Petal:
spawn_bud(data.location, data.offset, data.depth) spawn_bud(node.location, node.offset, node.depth)
update_active_depth() update_active_depth()
else: fully_active = true
# Upon entering the scene, select the applied status, then spawn the inactive vine
func _enter_tree() -> void: func _enter_tree() -> void:
var data : Dictionary = status_data.pick_random() var data : Dictionary = status_data.pick_random()
status_name = data.name status_name = data.name
@ -150,27 +169,21 @@ func _enter_tree() -> void:
img_path_active = data.img_path img_path_active = data.img_path
init_random() init_random()
func random_vine_node_at(location): # Initializes a random vine
var offset = random_offset()
return VineNode.new(self, location, offset)
func init_random(): func init_random():
# First, include the petal
Grid.add_vine_to(self, petal.location) Grid.add_vine_to(self, petal.location)
vine_locations.append(petal.location) vine_locations.append(petal.location)
vine_end_data.append(petal) vine_end_data.append(petal)
for i in range(randi_range(2,2)): # Attempt to grow a new vine for a total 6 - 12 times
var grow_attempts = randi_range(6,12)
while grow_attempts > 0:
# Attempt to grow from a random end to 1 - 4 random directions
var end = vine_end_data.pick_random() var end = vine_end_data.pick_random()
var branches_count = 0 for branch in range(min(ceil(randf() * 4), grow_attempts)):
for branch in range(ceil(randf() * 4)): grow_attempts -= 1
var dir = [Vector2.UP, Vector2.DOWN, Vector2.RIGHT, Vector2.LEFT].pick_random() var dir = [Vector2.UP, Vector2.DOWN, Vector2.RIGHT, Vector2.LEFT].pick_random()
var target_location = Global.vec_mod(end.location + dir, Grid.num_collumns, true) var target_location = Global.vec_mod(end.location + dir, Grid.num_collumns, true)
if target_location.y <= Grid.max_bud_height + 1 and Grid.get_vines_at(target_location).is_empty(): if target_location.y <= Grid.max_bud_height + 1 and Grid.get_vines_at(target_location).is_empty():
if not (target_location.y <= 0 or target_location.y > Grid.max_bud_height): var target = GridNode.random_at(target_location)
branches_count += 1
var target = random_vine_node_at(target_location)
grow_vine_sequence(end, target, true, true) grow_vine_sequence(end, target, true, true)
if i==0 and branches_count == 1:
vine_end_data.append(petal)
func random_offset():
return Vector2(randf_range(60, 240), randf_range(90, 270))

View file

@ -6,40 +6,43 @@ class_name BuildingGenerator extends Node
@export var only_on_first_load = false @export var only_on_first_load = false
static var first_load = true static var first_load = true
func random_oppostite_collumn() -> int: # Determine the player's column, then choose one in the opposite third of the circle
var playerpos = %Player.position func random_opposite_collumn() -> int:
var player_angle = atan2(playerpos.y, playerpos.x) var player_location = Grid.get_location_from_world_pos(%Player.position)
var offset = randi_range(int(Grid.num_collumns / 3.0), int(2 * Grid.num_collumns / 3.0))
var offset = randf_range(TAU/3, 2*TAU/3) var collumn = player_location.x + offset
var spawn_angle = player_angle + offset
var collumn = int(spawn_angle / TAU * Grid.num_collumns + Grid.num_collumns) % Grid.num_collumns
return collumn return collumn
func random_collumn() -> int: func random_collumn() -> int:
return randi_range(0, Grid.num_collumns - 1) return randi_range(0, Grid.num_collumns - 1)
func _ready(): func _ready():
# The initial buildings in the main menu are only to be spawned upon first loading
if not (only_on_first_load and not first_load): if not (only_on_first_load and not first_load):
first_load = false first_load = false
for i in range(initial_buildings): for i in range(initial_buildings):
# For each building, attempt spawns a few times.
# Spawns are not viable if they are within the player spawn protection
# or overlap with existing buildings
for j in range(spawn_attempts): for j in range(spawn_attempts):
var collumn = random_collumn() var collumn = random_collumn()
if initial_spawn_protection and 43 <= collumn and collumn <= 49: if initial_spawn_protection and 43 <= collumn and collumn <= 49:
continue continue
var building = randomize_building() var building = random_building()
building.z_index = -2
if Grid.add_building_to_collumn(building, collumn): if Grid.add_building_to_collumn(building, collumn):
break break
# Each time the building generator's timer runs out, generate a new building
func _on_timer_timeout() -> void: func _on_timer_timeout() -> void:
for i in range(spawn_attempts): for i in range(spawn_attempts):
var collumn = random_oppostite_collumn() var collumn = random_opposite_collumn()
var building : Building = randomize_building() var building : Building = random_building()
building.z_index = -2
if Grid.add_building_to_collumn(building, collumn): if Grid.add_building_to_collumn(building, collumn):
break break
func randomize_building() -> Building: # Picks a random building from the list. Sets the z_index.
func random_building() -> Building:
var index = randi() % Grid.packed_buildings.size() var index = randi() % Grid.packed_buildings.size()
return Grid.packed_buildings[index].instantiate() var ret = Grid.packed_buildings[index].instantiate()
ret.z_index = -2
return ret

View file

@ -1,5 +0,0 @@
extends Node2D
@export var radius : float;
func _draw():
draw_circle(Vector2.ZERO, radius, Color.BLACK, true, -1.0, true)

View file

@ -1 +0,0 @@
uid://b5fhsy1xlreco

View file

@ -3,7 +3,7 @@ extends Node2D
@export var grass : PackedScene @export var grass : PackedScene
func _ready() -> void: func _ready() -> void:
ItemSpawn.item_pool = ResourceLoader.load("res://items/generic/item_pool.tres","",ResourceLoader.CACHE_MODE_IGNORE) # Place grass
for column in range(Grid.num_collumns): for column in range(Grid.num_collumns):
var grass_placed : Building = grass.instantiate() var grass_placed : Building = grass.instantiate()
grass_placed.location = Vector2(column, 0) grass_placed.location = Vector2(column, 0)

View file

@ -42,15 +42,33 @@ func add_building_to_collumn(building : Building, collumn : int):
building.free() building.free()
return false return false
add_child(building) add_child(building)
return true return true
# Adds children of given node to the grid and their building.
func place_object_list(obj_list : Node2D, building):
obj_list.reparent(self, false)
var objects_to_be_placed = obj_list.get_children()
for object in objects_to_be_placed:
var offset = object.global_position;
object.global_position = Grid.get_world_position(building.location, offset)
# The building remembers these objects: If it is destroyed, so are they.
if object is Platform or object is Trap or object is Item:
building.objects.append(object)
if "building" in object: object.building = self
# This scales platforms hoizontally to make sure they still form a floor without gaps.
if(object.has_method("init_at_horizontal_distortion")):
object.init_at_horizontal_distortion(object.position.length() / Grid.ground_radius)
grid_entrance_callback(object)
# Returns the global position for a given grid location and offset
func get_world_position (location: Vector2, offset: Vector2 = Vector2.ZERO) -> Vector2: func get_world_position (location: Vector2, offset: Vector2 = Vector2.ZERO) -> Vector2:
var height = ground_radius + location.y * cell_height - offset.y # currently assumes anchor is bottom left var height = ground_radius + location.y * cell_height - offset.y # currently assumes anchor is bottom left
var angle = (location.x + offset.x / cell_height) * TAU / num_collumns var angle = (location.x + offset.x / cell_height) * TAU / num_collumns
return height * Vector2.from_angle(angle) return height * Vector2.from_angle(angle)
# Returns the grid location for a given global position
func get_location_from_world_pos(pos : Vector2): func get_location_from_world_pos(pos : Vector2):
var angle = fposmod(pos.angle(), TAU) var angle = fposmod(pos.angle(), TAU)
var x = floor(num_collumns * angle / TAU) var x = floor(num_collumns * angle / TAU)
@ -58,6 +76,7 @@ func get_location_from_world_pos(pos : Vector2):
var y = ceil((height - ground_radius)/cell_height) var y = ceil((height - ground_radius)/cell_height)
return Vector2(x, y) return Vector2(x, y)
# Returns the offset with respect to the grid location for a given global position
func get_offset_from_world_pos(pos : Vector2): func get_offset_from_world_pos(pos : Vector2):
var angle = pos.angle() var angle = pos.angle()
var x = fposmod(num_collumns * angle / TAU, 1) * cell_height var x = fposmod(num_collumns * angle / TAU, 1) * cell_height
@ -65,7 +84,10 @@ func get_offset_from_world_pos(pos : Vector2):
var y = fposmod(-(height - ground_radius)/cell_height, 1) * cell_height var y = fposmod(-(height - ground_radius)/cell_height, 1) * cell_height
return Vector2(x, y) return Vector2(x, y)
# Resets objects in the grids and the item pool.
# Also initializes vines_per_node.
func reset(): func reset():
ItemSpawn.item_pool = ResourceLoader.load("res://items/generic/item_pool.tres","",ResourceLoader.CACHE_MODE_IGNORE)
for obj in get_children(): for obj in get_children():
obj.free() obj.free()
buildings = [] buildings = []
@ -76,22 +98,22 @@ func reset():
arr.append([]) arr.append([])
vines_per_node.append(arr) vines_per_node.append(arr)
# Returns all vines present at given grid location.
func get_vines_at(location) -> Array: func get_vines_at(location) -> Array:
location = Global.vec_mod(location, num_collumns, true) location = Global.vec_mod(location, num_collumns, true)
return vines_per_node[location.x][location.y] return vines_per_node[location.x][location.y]
# Registers a vine at a given grid location.
func add_vine_to(vine, location) -> void: func add_vine_to(vine, location) -> void:
if location.y > max_bud_height + 1 or location.y < 0: if location.y > max_bud_height + 1 or location.y < 0:
return return
location = Global.vec_mod(location, num_collumns, true) location = Global.vec_mod(location, num_collumns, true)
vines_per_node[location.x][location.y].append(vine) vines_per_node[location.x][location.y].append(vine)
# for testing # Calls _enter_grid on all children.
#func _ready() -> void: func grid_entrance_callback(object : Node):
# # Objects receive a callback when placed, starting from the deepest children
# for child in object.get_children():
# grid_entrance_callback(child)
#for i in range(100): if object.has_method("_enter_grid"):
#var test_building = packed_buildings[0].instantiate() object.call_deferred("_enter_grid")
#var collumn = randi() % 60
#add_building_to_collumn(test_building, collumn)