TODO: Fix UI Button reaching 0 not greying out, fix state behaviour for selected tiles

This commit is contained in:
Sch1nken 2024-03-06 19:55:13 +01:00
parent b9df0b4361
commit 5b79dc9822
9 changed files with 325 additions and 95 deletions

View file

@ -21,18 +21,23 @@ var used_cells: Dictionary = {}
# have all used_cells be saved as Vector4i (q, r, s, y)
class CellStorage:
var cells: Dictionary = {}
class TileStorage:
var tiles: Dictionary = {}
# we use a vector4i for coordinates
# q r s y (layer)
func add_cell(coords: CubeCoordinates, layer: int = 0) -> void:
func add_tile(tile: InsectTile, coords: CubeCoordinates, layer: int = 0) -> void:
tiles[Vector4i(coords.q, coords.r, coords.s, layer)] = tile
pass
func remove_cell(coords: CubeCoordinates, layer: int = 0) -> void:
func remove_tile(coords: CubeCoordinates, layer: int = 0) -> void:
pass
func has_cell(cords: CubeCoordinates, layer: int = 0) -> bool:
return false
func has_tile(coords: CubeCoordinates, layer: int = 0) -> bool:
return tiles.has(Vector4i(coords.q, coords.r, coords.s, layer))
func get_tile(coords: CubeCoordinates, layer: int = 0) -> InsectTile:
return tiles[Vector4i(coords.q, coords.r, coords.s, layer)]
class CubeCoordinates:
@ -62,6 +67,9 @@ 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: CubeCoordinates) -> 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)
@ -118,16 +126,23 @@ func get_3d_pos(position2D: Vector2):
var placements: Dictionary = {}
func is_cell_empty(coords: Vector2i) -> bool:
return !used_cells.has(coords)
func is_cell_empty(coords: CubeCoordinates) -> bool:
return !used_cells.has(Vector4i(coords.q, coords.r, coords.s, 0))
func get_empty_neighbours(coords: Vector2i) -> Array[Vector2i]:
func is_cell_not_empty(coords: CubeCoordinates) -> bool:
return !is_cell_empty(coords)
func get_empty_neighbours(coords: CubeCoordinates) -> Array[CubeCoordinates]:
return get_neighbours(coords).filter(is_cell_empty)
func get_neighbours(coords: Vector2i) -> Array[Vector2i]:
func get_neighbours(coords: CubeCoordinates) -> Array[CubeCoordinates]:
return [
Vector2i(coords.x + 1, coords.y), Vector2i(coords.x + 1, coords.y - 1), Vector2i(coords.x, coords.y - 1),
Vector2i(coords.x - 1, coords.y), Vector2i(coords.x - 1, coords.y + 1), Vector2i(coords.x, coords.y + 1)
CubeCoordinates.new(coords.q + 1, coords.r, coords.s - 1),
CubeCoordinates.new(coords.q + 1, coords.r - 1, coords.s),
CubeCoordinates.new(coords.q, coords.r - 1, coords.s + 1),
CubeCoordinates.new(coords.q - 1, coords.r, coords.s + 1),
CubeCoordinates.new(coords.q - 1, coords.r + 1, coords.s),
CubeCoordinates.new(coords.q, coords.r + 1, coords.s - 1)
]
var current_tile: Node3D
@ -145,27 +160,28 @@ func _on_insect_selected(insect_resource: TileResource, is_black: bool) -> void:
# spawn possible placement locations :)
if used_cells.size() == 0: # we have no cells placed, display a placement outline at 0, 0
var outline = HEX_OUTLINE.instantiate()
var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(0, 0))
var cubepos = CubeCoordinates.new(0, 0, 0)
var hex_pos = cube_to_world_pos(cubepos)
outline.position = Vector3(hex_pos.x, 0.0, hex_pos.y)
outline.hex_pos = Vector2i(0, 0)
outline.visible = true
outline.insect_resource = insect_resource
outline.is_black = is_black
outline.coordinates = cubepos
placement_visualizer.add_child(outline)
placements[hex_pos] = outline
elif used_cells.size() == 1: # we have ONE cell placed, this is a special case in which
# the opposing player is allowed to place a tile that touches the enemy color
# We display outline placement around all spaces of this single cell
var single_cell = used_cells.keys().front()
var neighbours = get_neighbours(single_cell)
var neighbours = get_neighbours(CubeCoordinates.new(single_cell.x, single_cell.y, single_cell.z))
for neighbour in neighbours:
var outline = HEX_OUTLINE.instantiate()
var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(neighbour.x, neighbour.y))
var hex_pos = cube_to_world_pos(neighbour)
outline.position = Vector3(hex_pos.x, 0.0, hex_pos.y)
outline.hex_pos = neighbour
outline.visible = true
outline.insect_resource = insect_resource
outline.is_black = is_black
outline.coordinates = neighbour
placement_visualizer.add_child(outline)
placements[hex_pos] = outline
else:
@ -174,40 +190,35 @@ func _on_insect_selected(insect_resource: TileResource, is_black: bool) -> void:
var possible_placements: Dictionary = {}
for hex in used_cells.keys():
var neighbours = [
Vector2i(hex.x + 1, hex.y), Vector2i(hex.x + 1, hex.y - 1), Vector2i(hex.x, hex.y - 1),
Vector2i(hex.x - 1, hex.y), Vector2i(hex.x - 1, hex.y + 1), Vector2i(hex.x, hex.y + 1)
]
#var eligible: bool = true
for neighbour in neighbours:
if not used_cells.has(neighbour):
possible_placements[neighbour] = true
for neighbour in get_empty_neighbours(CubeCoordinates.new(hex.x, hex.y, hex.z)):
if not used_cells.has(Vector4(neighbour.q, neighbour.r, neighbour.s, 0)):
possible_placements[Vector4i(neighbour.q, neighbour.r, neighbour.s, 0)] = true
for p in possible_placements:
var neighbours = [
Vector2i(p.x + 1, p.y), Vector2i(p.x + 1, p.y - 1), Vector2i(p.x, p.y - 1),
Vector2i(p.x - 1, p.y), Vector2i(p.x - 1, p.y + 1), Vector2i(p.x, p.y + 1)
]
#var neighbours = [
# Vector2i(p.x + 1, p.y), Vector2i(p.x + 1, p.y - 1), Vector2i(p.x, p.y - 1),
# Vector2i(p.x - 1, p.y), Vector2i(p.x - 1, p.y + 1), Vector2i(p.x, p.y + 1)
#]
var eligible: bool = true
for neighbour in neighbours:
if not used_cells.has(neighbour):
for neighbour in get_neighbours(CubeCoordinates.new(p.x, p.y, p.z)):
if not used_cells.has(Vector4i(neighbour.q, neighbour.r, neighbour.s, 0)):
continue
if used_cells[neighbour].is_black != is_black:
if used_cells[Vector4i(neighbour.q, neighbour.r, neighbour.s, 0)].is_black != is_black:
eligible = false
break
if eligible:
var outline = HEX_OUTLINE.instantiate()
var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(p.x, p.y))
var hex_pos = cube_to_world_pos(CubeCoordinates.new(p.x, p.y, p.z))
outline.position = Vector3(hex_pos.x, 0.0, hex_pos.y)
outline.hex_pos = p
outline.visible = true
outline.insect_resource = insect_resource
outline.is_black = is_black
outline.coordinates = CubeCoordinates.new(p.x, p.y, p.z)
placement_visualizer.add_child(outline)
placements[p] = outline
@ -223,9 +234,9 @@ func _on_insect_placement_cancelled() -> void:
for child in placement_visualizer.get_children():
child.queue_free()
func _on_insect_placed(resource: TileResource, is_black: bool, pos: Vector2i) -> void:
func _on_insect_placed(resource: TileResource, is_black: bool, pos: CubeCoordinates) -> void:
var tile_copy = INSECT_TILE.instantiate()
var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(pos.x, pos.y))
var hex_pos = cube_to_world_pos(pos)
tile_copy.position = Vector3(hex_pos.x, 20.0, hex_pos.y)
tile_copy.resource = resource
@ -233,7 +244,7 @@ func _on_insect_placed(resource: TileResource, is_black: bool, pos: Vector2i) ->
tile_copy.coordinates = pos
var target_pos = Vector3(hex_pos.x, 0.0, hex_pos.y)
used_cells[Vector2i(pos.x, pos.y)] = tile_copy
used_cells[Vector4i(pos.q, pos.r, pos.s, 0)] = tile_copy
add_child(tile_copy)
@ -244,14 +255,34 @@ func _on_insect_tile_selected(tile: InsectTile) -> void:
if tile.resource.movement_behaviour == null:
return
var pos = world_to_hex_tile(Vector2(tile.position.x, tile.position.z))
var spaces = tile.resource.movement_behaviour.get_available_spaces(Vector2i(pos.q, pos.r), self)
var spaces = tile.resource.movement_behaviour.get_available_spaces(tile.coordinates, self)
print(spaces.size())
if spaces.is_empty():
GameEvents.insect_tile_selection_request_failed.emit(tile)
return
for space in spaces:
var neighbours = get_neighbours(space)
# if all neighbours are empty, move would disconnect us from the hive
# so we discard it
# also: if there are 5 empty space and the only remaining one is our current tile...
# we would also be disconnected after the move
# maybe the 6 check is not needed
var non_empty_neighbours = neighbours.filter(is_cell_not_empty)
var coords_vec4: Vector4i = Vector4i(tile.coordinates.q, tile.coordinates.r, tile.coordinates.s, 0)
if non_empty_neighbours.size() == 1:
var occupied_neighbour = non_empty_neighbours.front()
var neighbour_vec4: Vector4i = Vector4i(occupied_neighbour.q, occupied_neighbour.r, occupied_neighbour.s, 0)
if neighbour_vec4 == coords_vec4:
continue
var outline = HEX_OUTLINE.instantiate()
var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(space.x, space.y))
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, 0.0, hex_pos.y)
outline.hex_pos = space
outline.coordinates = space
outline.visible = true
outline.insect_tile = tile
outline.is_moving = true
@ -261,10 +292,10 @@ func _on_insect_tile_selected(tile: InsectTile) -> void:
placements[space] = outline
func _on_insect_tile_moved(tile: InsectTile, target: Vector2i) -> void:
used_cells.erase(tile.coordinates)
func _on_insect_tile_moved(tile: InsectTile, target: CubeCoordinates) -> void:
used_cells.erase(Vector4i(tile.coordinates.q, tile.coordinates.r, tile.coordinates.s, 0))
var new_hex_pos = flat_hex_to_world_position(AxialCoordinates.new(target.x, target.y))
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, 0.0, new_hex_pos.y)
#
@ -278,7 +309,43 @@ func _on_insect_tile_moved(tile: InsectTile, target: Vector2i) -> void:
tile.coordinates = target
used_cells[target] = tile
used_cells[Vector4i(target.q, target.r, target.s, 0)] = tile
func can_hive_exist_without_tile(tile: InsectTile) -> bool:
# 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
return true
var vector_coords: Vector4i = Vector4i(tile.coordinates.q, tile.coordinates.r, tile.coordinates.s, 0)
# DO BFS
var tiles_reached: Array = []
var tiles_available: Array = used_cells.keys().filter(func(coords): return coords != vector_coords)
# 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(CubeCoordinates.new(m.x, m.y, m.z)):
var neighbour_vec4: Vector4i = Vector4i(neighbour.q, neighbour.r, neighbour.s, 0)
if neighbour_vec4 not in tiles_reached and neighbour_vec4 != vector_coords:
if used_cells.has(neighbour_vec4):
tiles_reached.push_back(neighbour_vec4)
queue.push_back(neighbour_vec4)
return tiles_reached.size() == used_cells.size() - 1
func _on_insect_tile_request_selection(tile: InsectTile) -> void:
if can_hive_exist_without_tile(tile):
GameEvents.insect_tile_selection_request_successful.emit(tile)
else:
GameEvents.insect_tile_selection_request_failed.emit(tile)
func _ready() -> void:
GameEvents.insect_selected.connect(_on_insect_selected)
@ -286,25 +353,8 @@ func _ready() -> void:
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_request_selection.connect(_on_insect_tile_request_selection)
return
for x in range(-6, 5):
for y in range(-6, 5):
var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(x, y))
if randi_range(0, 1) == 0:
var new_hex = INSECT_TILE.instantiate()
new_hex.resource = preload("res://Tile/Prefabs/Bee.tres")
new_hex.is_black = false
new_hex.position = Vector3(hex_pos.x, 0.0, hex_pos.y)
var hex_id = world_to_hex_tile(Vector2(hex_pos.x, hex_pos.y))
add_child(new_hex)
used_cells[Vector2i(x, y)] = new_hex
else:
continue
#func spawn_random_tile() -> void:
#var tile_copy = hex.duplicate()
#var hex_pos = flat_hex_to_world_position(AxialCoordinates.new(randi_range(-20, 20), randi_range(-20, 20)))