594 lines
19 KiB
GDScript
594 lines
19 KiB
GDScript
extends Node3D
|
|
class_name HexGrid
|
|
|
|
@onready var placement_visualizer = $PlacementVisualizer
|
|
|
|
const DIR_N: Vector3 = Vector3(0, 1, -1)
|
|
const DIR_NE: Vector3 = Vector3(1, 0, -1)
|
|
const DIR_SE: Vector3 = Vector3(1, -1, 0)
|
|
const DIR_S: Vector3 = Vector3(0, -1, 1)
|
|
const DIR_SW: Vector3 = Vector3(-1, 0, 1)
|
|
const DIR_NW: Vector3 = Vector3(-1, 1, 0)
|
|
const DIR_ALL: Array[Vector3] = [DIR_N, DIR_NE, DIR_SE, DIR_S, DIR_SW, DIR_NW]
|
|
|
|
#const size = Vector2(1, sqrt(3.0)/2.0)
|
|
|
|
# We can hover all of our tiles (will show on-hover shader)
|
|
# If we click on a placed tile, we do the following
|
|
# Check if we would split the hive -> deny selection
|
|
# Get possible movement tiles (via MovementBehaviour)
|
|
# If 0 -> Deny
|
|
# Filter remaining movement spots to not include hive-splitting moves(?)
|
|
|
|
const size: float = 0.5
|
|
|
|
var used_cells: Dictionary = {}
|
|
|
|
@export var layer_height: float = 0.4
|
|
|
|
# have all used_cells be saved as Vector4i (q, r, s, y)
|
|
|
|
class AxialCoordinates:
|
|
var q: float
|
|
var r: float
|
|
|
|
func _init(_q: float, _r: float):
|
|
q = _q
|
|
r = _r
|
|
|
|
func flat_hex_corner(center: Vector2, size: float, corner_num: int) -> Vector2:
|
|
var angle_deg: int = 60 * corner_num
|
|
var angle_rad: float = deg_to_rad(angle_deg)
|
|
return Vector2(center.x + size * cos(angle_rad), center.y + size * sin(angle_rad))
|
|
|
|
func flat_hex_to_world_position(coords: AxialCoordinates) -> Vector2:
|
|
var x = size * (3.0/2.0 * coords.q)
|
|
var y = size * (sqrt(3.0)/2.0 * coords.q + sqrt(3.0) * coords.r)
|
|
return Vector2(x, y)
|
|
|
|
func cube_to_world_pos(coords: Vector4i) -> Vector2:
|
|
return flat_hex_to_world_position(cube_to_axial(coords))
|
|
|
|
#func world_to_hex_tile(world_pos: Vector3) -> Vector2:
|
|
# var q = (2.0/3.0 * world_pos.x)
|
|
# var r = (-1.0/3.0 * world_pos.x + sqrt(3.0)/3.0 * world_pos.z)
|
|
#
|
|
# return cube_round()
|
|
#
|
|
# return
|
|
|
|
const INSECT_TILE = preload("res://InsectTiles/InsectTile.tscn")
|
|
|
|
func world_to_hex_tile(coords: Vector2) -> AxialCoordinates:
|
|
var q = (2.0/3.0 * coords.x) / size
|
|
var r = (-1.0/3.0 * coords.x + sqrt(3.0)/3.0 * coords.y) / size
|
|
return axial_round(AxialCoordinates.new(q, r))
|
|
|
|
func cube_to_axial(coords: Vector4i) -> AxialCoordinates:
|
|
var q = coords.x
|
|
var r = coords.y
|
|
return AxialCoordinates.new(q, r)
|
|
|
|
func axial_round(coords: AxialCoordinates) -> AxialCoordinates:
|
|
return cube_to_axial(cube_round(axial_to_cube(coords)))
|
|
|
|
func axial_to_cube(coords: AxialCoordinates) -> Vector4i:
|
|
var q = coords.q
|
|
var r = coords.r
|
|
var s = -q-r
|
|
return Vector4i(q, r, s, 0)
|
|
|
|
func cube_round(coords: Vector4i) -> Vector4i:
|
|
var q: float = round(coords.x)
|
|
var r: float = round(coords.y)
|
|
var s: float = round(coords.z)
|
|
|
|
var q_diff: float = abs(q - coords.x)
|
|
var r_diff: float = abs(r - coords.y)
|
|
var s_diff: float = abs(s - coords.z)
|
|
|
|
if q_diff > r_diff and q_diff > s_diff:
|
|
q = -r-s
|
|
elif r_diff > s_diff:
|
|
r = -q-s
|
|
else:
|
|
s = -q-r
|
|
|
|
return Vector4i(q, r, s, 0)
|
|
|
|
@export var dragging_intersect_plane_normal: Vector3 = Vector3.UP
|
|
@export var dragging_intersect_plane_distance: float = 0.0
|
|
|
|
func get_3d_pos(position2D: Vector2):
|
|
return Plane(dragging_intersect_plane_normal, dragging_intersect_plane_distance).intersects_ray(get_viewport().get_camera_3d().project_ray_origin(position2D), get_viewport().get_camera_3d().project_ray_normal(position2D))
|
|
|
|
var placements: Dictionary = {}
|
|
|
|
func is_cell_empty(coords: Vector4i) -> bool:
|
|
return !used_cells.has(coords)
|
|
|
|
func is_cell_not_empty(coords: Vector4i) -> bool:
|
|
return !is_cell_empty(coords)
|
|
|
|
func get_empty_neighbours(coords: Vector4i) -> Array[Vector4i]:
|
|
return get_neighbours(coords).filter(is_cell_empty)
|
|
|
|
func get_highest_in_stack(coords: Vector4i) -> Vector4i:
|
|
if not used_cells.has(coords):
|
|
#print("ground")
|
|
return coords
|
|
|
|
var top: InsectTile = used_cells[coords]
|
|
while top.hat != null:
|
|
top = top.hat
|
|
|
|
#print("found top")
|
|
#print(top.coordinates)
|
|
return top.coordinates
|
|
|
|
func get_neighbours(coords: Vector4i, ground_layer: bool = false) -> Array[Vector4i]:
|
|
var layer: int = coords.w
|
|
if ground_layer:
|
|
layer = 0
|
|
|
|
return [
|
|
Vector4i(coords.x + 1, coords.y, coords.z - 1, layer),
|
|
Vector4i(coords.x + 1, coords.y - 1, coords.z, layer),
|
|
Vector4i(coords.x, coords.y - 1, coords.z + 1, layer),
|
|
Vector4i(coords.x - 1, coords.y, coords.z + 1, layer),
|
|
Vector4i(coords.x - 1, coords.y + 1, coords.z, layer),
|
|
Vector4i(coords.x, coords.y + 1, coords.z - 1, layer)
|
|
]
|
|
|
|
const HEX_OUTLINE = preload("res://hex_outline.tscn")
|
|
|
|
func get_placeable_positions(button: InsectButton) -> Array[Vector4i]:
|
|
if used_cells.size() == 0:
|
|
return [Vector4i.ZERO]
|
|
elif used_cells.size() == 1:
|
|
var single_cell = used_cells.keys().front()
|
|
var neighbours = get_neighbours(single_cell)
|
|
var positions: Array[Vector4i] = []
|
|
|
|
for neighbour in neighbours:
|
|
#var hex_pos = cube_to_world_pos(neighbour)
|
|
positions.push_back(neighbour)
|
|
return positions
|
|
|
|
var possible_placements: Dictionary = {}
|
|
var positions: Array[Vector4i] = []
|
|
|
|
for hex in used_cells.keys().filter(func(coords): return coords.w == 0):
|
|
# We filter here because we only want neighbours of ground level tiles
|
|
# Otherwise we spawn an oultine on ground level but with an internal
|
|
# Coordinate of somewhere higher up
|
|
# Visually everything will be correct but internally the resulting hex
|
|
# Will count as higher layer tile leading to nasty bugs
|
|
|
|
for neighbour in get_empty_neighbours(hex):
|
|
if not used_cells.has(neighbour):
|
|
possible_placements[neighbour] = true
|
|
|
|
for p in possible_placements:
|
|
var eligible: bool = true
|
|
|
|
for neighbour in get_neighbours(p):
|
|
if not used_cells.has(neighbour):
|
|
continue
|
|
|
|
if used_cells[get_highest_in_stack(neighbour)].is_black != button.is_black:
|
|
eligible = false
|
|
break
|
|
|
|
if eligible:
|
|
positions.push_back(p)
|
|
|
|
return positions
|
|
|
|
|
|
func get_left_neighbour(pos: Vector4i) -> Vector4i:
|
|
return Vector4i(-pos.z, -pos.x, -pos.y, 0)
|
|
|
|
func get_right_neighbour(pos: Vector4i) -> Vector4i:
|
|
return Vector4i(-pos.y, -pos.z, -pos.x, 0)
|
|
|
|
var debug_labels = []
|
|
|
|
func debug_label(pos, text) -> void:
|
|
var label = Label3D.new()
|
|
label.billboard = BaseMaterial3D.BILLBOARD_ENABLED
|
|
label.text = text
|
|
label.no_depth_test = true
|
|
var p = cube_to_world_pos(pos)
|
|
label.position = Vector3(p.x, 0.2, p.y)
|
|
add_child(label)
|
|
debug_labels.push_back(label)
|
|
|
|
func clear_debug_labels() -> void:
|
|
for label in debug_labels:
|
|
label.queue_free()
|
|
|
|
debug_labels.clear()
|
|
|
|
func can_reach(start: Vector4i, target: Vector4i, exclude: Array[Vector4i] = []) -> bool:
|
|
if start.w != target.w:
|
|
return true
|
|
|
|
# if we have 5 potential spaces it can never be blocked
|
|
var offset: Vector4i = Vector4i.ZERO
|
|
|
|
offset.x = target.x - start.x
|
|
offset.y = target.y - start.y
|
|
offset.z = target.z - start.z
|
|
|
|
var left = get_left_neighbour(offset)
|
|
var right = get_right_neighbour(offset)
|
|
|
|
var left_coord = Vector4i(left.x + start.x, left.y + start.y, left.z + start.z, start.w)
|
|
var right_coord = Vector4i(right.x + start.x, right.y + start.y, right.z + start.z, start.w)
|
|
|
|
if left_coord in exclude or right_coord in exclude:
|
|
#print("excluded?")
|
|
return true
|
|
|
|
|
|
return is_cell_empty(left_coord) or is_cell_empty(right_coord)
|
|
|
|
func _on_insect_selected(button: InsectButton, is_black: bool) -> void:
|
|
var positions = get_placeable_positions(button)
|
|
|
|
for child in placement_visualizer.get_children():
|
|
child.queue_free()
|
|
|
|
for p in positions:
|
|
var outline = HEX_OUTLINE.instantiate()
|
|
var hex_pos = cube_to_world_pos(p)
|
|
outline.position = Vector3(hex_pos.x, 0.0, hex_pos.y)
|
|
outline.visible = true
|
|
outline.insect_resource = button.insect_resource
|
|
outline.is_black = is_black
|
|
outline.coordinates = p
|
|
outline.map_reference = self
|
|
placement_visualizer.add_child(outline)
|
|
|
|
func _on_insect_placement_cancelled() -> void:
|
|
for child in placement_visualizer.get_children():
|
|
child.queue_free()
|
|
|
|
@rpc("any_peer", "call_local")
|
|
func place_insect_tile(resource_path: String, is_black: bool, pos: Vector4i) -> void:
|
|
var resource = load(resource_path)
|
|
|
|
var tile_copy = INSECT_TILE.instantiate()
|
|
var hex_pos = cube_to_world_pos(pos)
|
|
|
|
tile_copy.position = Vector3(hex_pos.x, 20.0, hex_pos.y)
|
|
tile_copy.resource = resource
|
|
tile_copy.is_black = is_black
|
|
tile_copy.coordinates = pos
|
|
#print(pos)
|
|
tile_copy.map_reference = self
|
|
var target_pos = Vector3(hex_pos.x, 0.0, hex_pos.y)
|
|
|
|
used_cells[pos] = tile_copy
|
|
|
|
var sender_id = multiplayer.get_remote_sender_id()
|
|
|
|
tile_copy.set_multiplayer_authority(sender_id)
|
|
|
|
add_child(tile_copy)
|
|
|
|
GameEvents.insect_tile_created.emit(tile_copy, pos)
|
|
|
|
var tween = get_tree().create_tween()
|
|
tween.tween_property(tile_copy, "position", target_pos, 1.0).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
|
|
|
|
|
|
|
|
func _on_insect_placed(resource: TileResource, is_black: bool, pos: Vector4i) -> void:
|
|
var resource_path = resource.resource_path
|
|
place_insect_tile.rpc(resource_path, is_black, pos)
|
|
|
|
func can_move(tile: InsectTile) -> bool:
|
|
if not can_hive_exist_without_tile(tile):
|
|
return false
|
|
|
|
var spaces = tile.get_movement_behaviour().get_available_spaces(tile.coordinates, self)
|
|
|
|
if spaces.is_empty():
|
|
return false
|
|
|
|
return true
|
|
|
|
func has_action_targets(tile: InsectTile) -> bool:
|
|
if tile.get_action_behaviour() == null:
|
|
return false
|
|
|
|
var targets: Array[InsectTile] = tile.get_action_behaviour().get_targets(tile.coordinates, self)
|
|
|
|
return !targets.is_empty()
|
|
|
|
func _on_insect_tile_action_started(tile: InsectTile) -> void:
|
|
do_action(tile)
|
|
|
|
func _on_insect_tile_move_started(tile: InsectTile) -> void:
|
|
do_move(tile)
|
|
|
|
func do_action(tile: InsectTile) -> void:
|
|
# get possible targets, pass the resource action callable with binds of source and target tile
|
|
var targets = tile.get_action_behaviour().get_targets(tile.coordinates, self)
|
|
|
|
for target in targets:
|
|
print("target?")
|
|
target.action_callback = tile.get_action_behaviour().do_action.bind(tile, target, self)
|
|
target.selected_for_action = true
|
|
|
|
target.highlight_for_action()
|
|
|
|
pass
|
|
|
|
|
|
pass
|
|
|
|
func do_move_as(source: InsectTile, copy: InsectTile) -> void:
|
|
if not can_hive_exist_without_tile(source):
|
|
print("Cant to do move as. Cant exist without hive")
|
|
return
|
|
|
|
for child in placement_visualizer.get_children():
|
|
child.queue_free()
|
|
|
|
var spaces = copy.get_movement_behaviour().get_available_spaces(source.coordinates, self)
|
|
|
|
if spaces.is_empty():
|
|
print("empty?")
|
|
#GameEvents.insect_tile_selection_request_failed.emit(tile)
|
|
return
|
|
|
|
for space in spaces:
|
|
var neighbours = get_neighbours(space)
|
|
var non_empty_neighbours = neighbours.filter(is_cell_not_empty)
|
|
|
|
if non_empty_neighbours.size() == 1:
|
|
# NOTE: This is correct! But seemed wrong when testing the beetle movement
|
|
# If there are only two tiles (beetle + some other) the beetle can't climb ontop of the other
|
|
# tile. (would not necessarily split the hive, but the simple logic I use thinks so).
|
|
# This fixes itself automatically when there are more than two tiles present
|
|
# And since you can't move unless you place the bee, there will always be at least 3 tiles
|
|
# before you can move your beetle
|
|
|
|
# NOTE: This MIGHT result in a bug when you stack beetles... but no I don't think so
|
|
# You'd need to have a bee to be able to move, so yeah
|
|
|
|
var occupied_neighbour = non_empty_neighbours.front()
|
|
if occupied_neighbour == source.coordinates:
|
|
# TODO: Check if this is stil correct?
|
|
continue
|
|
|
|
var layer: int = 0
|
|
var temp_tile: InsectTile = null
|
|
if is_cell_not_empty(space):
|
|
temp_tile = used_cells.get(space)
|
|
layer = 1
|
|
while temp_tile.hat != null:
|
|
layer += 1
|
|
temp_tile = temp_tile.hat
|
|
#print(layer)
|
|
|
|
space.w = layer
|
|
|
|
var outline = HEX_OUTLINE.instantiate()
|
|
var hex_pos = cube_to_world_pos(space) # flat_hex_to_world_position(AxialCoordinates.new(space.x, space.y))
|
|
outline.position = Vector3(hex_pos.x, layer * layer_height, hex_pos.y)
|
|
outline.coordinates = space
|
|
outline.visible = true
|
|
outline.insect_tile = source
|
|
outline.is_moving = true
|
|
outline.insect_resource = source.resource
|
|
outline.is_black = source.is_black
|
|
placement_visualizer.add_child(outline)
|
|
placements[space] = outline
|
|
|
|
func create_move_tiles(tile: InsectTile, coords: Array[Vector4i]) -> void:
|
|
for space in coords:
|
|
var layer: int = 0
|
|
var temp_tile: InsectTile = null
|
|
if is_cell_not_empty(space):
|
|
temp_tile = used_cells.get(space)
|
|
layer = 1
|
|
while temp_tile.hat != null:
|
|
layer += 1
|
|
temp_tile = temp_tile.hat
|
|
|
|
space.w = layer
|
|
|
|
var outline = HEX_OUTLINE.instantiate()
|
|
var hex_pos = cube_to_world_pos(space) # flat_hex_to_world_position(AxialCoordinates.new(space.x, space.y))
|
|
outline.position = Vector3(hex_pos.x, layer * layer_height, hex_pos.y)
|
|
outline.coordinates = space
|
|
outline.visible = true
|
|
outline.insect_tile = tile
|
|
outline.is_moving = true
|
|
outline.insect_resource = tile.resource
|
|
outline.is_black = tile.is_black
|
|
placement_visualizer.add_child(outline)
|
|
placements[space] = outline
|
|
|
|
func do_move(tile: InsectTile) -> void:
|
|
for child in placement_visualizer.get_children():
|
|
child.queue_free()
|
|
|
|
var spaces = tile.get_movement_behaviour().get_available_spaces(tile.coordinates, self)
|
|
|
|
if spaces.is_empty():
|
|
print("empty?")
|
|
#GameEvents.insect_tile_selection_request_failed.emit(tile)
|
|
return
|
|
|
|
for space in spaces:
|
|
var neighbours = get_neighbours(space)
|
|
var non_empty_neighbours = neighbours.filter(is_cell_not_empty)
|
|
|
|
if non_empty_neighbours.size() == 1:
|
|
# NOTE: This is correct! But seemed wrong when testing the beetle movement
|
|
# If there are only two tiles (beetle + some other) the beetle can't climb ontop of the other
|
|
# tile. (would not necessarily split the hive, but the simple logic I use thinks so).
|
|
# This fixes itself automatically when there are more than two tiles present
|
|
# And since you can't move unless you place the bee, there will always be at least 3 tiles
|
|
# before you can move your beetle
|
|
|
|
# NOTE: This MIGHT result in a bug when you stack beetles... but no I don't think so
|
|
# You'd need to have a bee to be able to move, so yeah
|
|
|
|
var occupied_neighbour = non_empty_neighbours.front()
|
|
if occupied_neighbour == tile.coordinates:
|
|
continue
|
|
|
|
var layer: int = 0
|
|
var temp_tile: InsectTile = null
|
|
if is_cell_not_empty(space):
|
|
temp_tile = used_cells.get(space)
|
|
layer = 1
|
|
while temp_tile.hat != null:
|
|
layer += 1
|
|
temp_tile = temp_tile.hat
|
|
#print(layer)
|
|
|
|
space.w = layer
|
|
|
|
var outline = HEX_OUTLINE.instantiate()
|
|
var hex_pos = cube_to_world_pos(space) # flat_hex_to_world_position(AxialCoordinates.new(space.x, space.y))
|
|
outline.position = Vector3(hex_pos.x, layer * layer_height, hex_pos.y)
|
|
outline.coordinates = space
|
|
outline.visible = true
|
|
outline.insect_tile = tile
|
|
outline.is_moving = true
|
|
outline.insect_resource = tile.resource
|
|
outline.is_black = tile.is_black
|
|
placement_visualizer.add_child(outline)
|
|
placements[space] = outline
|
|
|
|
func _on_insect_tile_selected(tile: InsectTile) -> void:
|
|
# check the following:
|
|
# if the insect is selectable for an action (has action_callback data set) -> do that action
|
|
# else:
|
|
# if the unit has no action
|
|
# try moving
|
|
# else:
|
|
# show action/move panel, grey out action/or move if there are no target or can't move?
|
|
if tile.action_callback.is_valid():
|
|
tile.action_callback.call()
|
|
return
|
|
else:
|
|
# if tile has an action
|
|
if tile.get_action_behaviour() != null:
|
|
GameEvents.choose_action_or_move.emit(tile, has_action_targets(tile), can_move(tile))
|
|
return
|
|
|
|
if can_move(tile):
|
|
do_move(tile)
|
|
|
|
func get_tile(pos: Vector4i) -> InsectTile:
|
|
return used_cells.get(pos)
|
|
|
|
@rpc("any_peer", "call_local")
|
|
func move_insect_tile(tile_coords: Vector4i, target: Vector4i) -> void:
|
|
var tile: InsectTile = used_cells[tile_coords]
|
|
|
|
# Remove from old stack
|
|
if tile.coordinates.w > 0:
|
|
var below: Vector4i = tile.coordinates + Vector4i(0, 0, 0, -1)
|
|
used_cells[below].hat = null
|
|
|
|
used_cells.erase(tile.coordinates)
|
|
|
|
var new_hex_pos = cube_to_world_pos(target)
|
|
var sky_new_hex_pos = Vector3(new_hex_pos.x, 20.0, new_hex_pos.y)
|
|
var ground_new_hex_pos = Vector3(new_hex_pos.x, target.w * layer_height, new_hex_pos.y)
|
|
|
|
var current_hex_pos = tile.position
|
|
var sky_current_hex_pos = tile.position + Vector3(0.0, 20.0, 0.0)
|
|
|
|
var tween = get_tree().create_tween()
|
|
tween.tween_property(tile, "position", sky_current_hex_pos, 0.5).set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_EXPO)
|
|
tween.tween_property(tile, "position", sky_new_hex_pos, 0.0)
|
|
tween.tween_property(tile, "position", ground_new_hex_pos, 1.0).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
|
|
|
|
tile.coordinates = target
|
|
|
|
used_cells[tile.coordinates] = tile
|
|
|
|
if tile.coordinates.w > 0:
|
|
var below: Vector4i = tile.coordinates + Vector4i(0, 0, 0, -1)
|
|
used_cells[below].hat = tile
|
|
|
|
GameEvents.insect_tile_finished_moving.emit(tile, target)
|
|
|
|
func _on_insect_tile_moved(tile: InsectTile, target: Vector4i) -> void:
|
|
move_insect_tile.rpc(tile.coordinates, target)
|
|
|
|
func get_same_neighbours(cell1: Vector4i, cell2: Vector4i) -> Array[Vector4i]:
|
|
var neighbours1 = get_neighbours(cell1).filter(is_cell_not_empty)
|
|
var neighbours2 = get_neighbours(cell2).filter(is_cell_not_empty)
|
|
|
|
var shared_neighbours: Array[Vector4i] = []
|
|
|
|
for n1 in neighbours1:
|
|
for n2 in neighbours2:
|
|
if n1 == n2:
|
|
if n1 not in shared_neighbours:
|
|
shared_neighbours.push_back(n1)
|
|
|
|
return shared_neighbours
|
|
|
|
func is_position_on_hive(pos: Vector4i) -> bool:
|
|
return get_empty_neighbours(pos).size() < 6
|
|
|
|
func can_hive_exist_without_tile(tile: InsectTile) -> bool:
|
|
if tile.coordinates.w != 0:
|
|
print("w")
|
|
return true
|
|
|
|
# TODO: BFS-Search from random cell to see if all other cells could still be reached when this
|
|
# tile would be empty space
|
|
if get_empty_neighbours(tile.coordinates).size() == 5: # we only have one real neighbour, so can't break anything
|
|
print("neighbours")
|
|
return true
|
|
|
|
# DO BFS
|
|
var tiles_reached: Array = []
|
|
var tiles_available: Array = used_cells.keys().filter(func(coords): return coords != tile.coordinates).filter(func(coords): return coords.w == 0)
|
|
|
|
#print(tiles_available)
|
|
|
|
if tiles_available.size() <= 1:
|
|
# If we only have 1 or 2 total tiles, we can always move
|
|
# 1 tile should never happen
|
|
# two... could theoretically but yeah
|
|
return true
|
|
|
|
# tiles_available has all remaining tiles, we just need to visit every tile from a (random) starting tile
|
|
# and compare the size with these of all tiles - 1 (our to be moved one)
|
|
var start: Vector4i = tiles_available.front()
|
|
tiles_reached.push_back(start)
|
|
var queue: Array[Vector4i] = [start]
|
|
|
|
while queue.size() > 0:
|
|
var m = queue.pop_front()
|
|
|
|
for neighbour in get_neighbours(m):
|
|
if neighbour not in tiles_reached and neighbour != tile.coordinates:
|
|
if used_cells.has(neighbour):
|
|
tiles_reached.push_back(neighbour)
|
|
queue.push_back(neighbour)
|
|
|
|
return tiles_reached.size() == tiles_available.size()
|
|
|
|
func _ready() -> void:
|
|
GameEvents.insect_selected.connect(_on_insect_selected)
|
|
GameEvents.insect_placement_cancelled.connect(_on_insect_placement_cancelled)
|
|
GameEvents.insect_placed.connect(_on_insect_placed)
|
|
GameEvents.insect_tile_selected.connect(_on_insect_tile_selected)
|
|
GameEvents.insect_tile_moved.connect(_on_insect_tile_moved)
|
|
GameEvents.insect_tile_action_started.connect(_on_insect_tile_action_started)
|
|
GameEvents.insect_tile_move_started.connect(_on_insect_tile_move_started)
|