207 lines
5.3 KiB
GDScript
207 lines
5.3 KiB
GDScript
extends Node2D
|
|
class_name Grid
|
|
|
|
@export var rows: int = 5
|
|
@export var cols: int = 5
|
|
@export var min_group_size: int = 3
|
|
|
|
@export var offset: float = 55.0
|
|
|
|
@onready
|
|
var grid_area: Area2D = $BoundaryArea
|
|
|
|
@onready
|
|
var grid_shape: CollisionShape2D = $BoundaryArea/BoundaryShape
|
|
|
|
|
|
var grid: Array[Array]
|
|
var groups: Array
|
|
var hovered_group: Array
|
|
|
|
var debug_label: Label
|
|
|
|
var token = preload("res://token.tscn")
|
|
|
|
func _ready():
|
|
debug_label = $"Debug Label"
|
|
|
|
grid_area.position = Vector2(cols * offset / 2, rows * offset / 2)
|
|
grid_shape.shape.size = Vector2(cols * offset, rows * offset)
|
|
|
|
for row in rows:
|
|
grid.append([])
|
|
for column in cols:
|
|
var token_node: Token = token.instantiate()
|
|
add_child(token_node)
|
|
token_node.set_type(randi_range(0,3) as Token.token_type)
|
|
#token_node.token_hovered.connect(_on_token_hovered.bind([row,column]))
|
|
grid[row].append(token_node)
|
|
|
|
redraw_grid()
|
|
calculate_token_groups()
|
|
|
|
func _process(_delta: float) -> void:
|
|
clear_highlights()
|
|
|
|
# get mouse position for hover
|
|
var mouse_position = self.get_local_mouse_position()
|
|
if not pixel_within_grid(mouse_position):
|
|
return
|
|
|
|
var coord_under_mouse = pixel_to_grid_coord(mouse_position)
|
|
var token_under_mouse: Token = grid[coord_under_mouse[0]][coord_under_mouse[1]]
|
|
|
|
if token_under_mouse != null:
|
|
var group = get_group_of_token(coord_under_mouse)
|
|
if group.size() >= min_group_size:
|
|
highlight_group(group, true)
|
|
|
|
# if click, determine token clicked
|
|
func pixel_within_grid(coord: Vector2) -> bool:
|
|
return (coord.x >= 0 and coord.x < cols * offset and
|
|
coord.y >= 0 and coord.y < rows * offset)
|
|
|
|
func pixel_to_grid_coord(coord: Vector2) -> Array[int]:
|
|
return [coord.y / offset, coord.x / offset]
|
|
|
|
|
|
func highlight_group(group: Array, enable: bool):
|
|
|
|
for coord in group:
|
|
var current_token = grid[coord[0]][coord[1]] as Token
|
|
if current_token == null: continue
|
|
current_token.set_highlighted(enable)
|
|
|
|
hovered_group = group
|
|
|
|
func clear_highlights():
|
|
for row in grid:
|
|
for token: Token in row:
|
|
if token != null:
|
|
token.set_highlighted(false)
|
|
|
|
func update_grid():
|
|
# search for empty cells and drop tokens above them down
|
|
for column in range(cols):
|
|
var col_array = []
|
|
for row in range(rows-1, -1, -1):
|
|
# create a temporary array from the column
|
|
col_array.append(grid[row][column])
|
|
|
|
# filter the nulls out of the array
|
|
col_array = col_array.filter(func(token): return token != null)
|
|
|
|
# put the filtered column back into the grid
|
|
for row in range(rows-1, -1, -1):
|
|
var idx = rows - row - 1
|
|
grid[row][column] = col_array[idx] if idx < col_array.size() else null
|
|
|
|
|
|
# search for empty coluns and shift tokens horizontally to fill them
|
|
var empty_columns = []
|
|
for column in range(cols):
|
|
var col_array = []
|
|
for row in range(rows):
|
|
col_array.append(grid[row][column])
|
|
|
|
if col_array.all(func(token): return token == null):
|
|
empty_columns.append(column)
|
|
|
|
if empty_columns.size() > 0:
|
|
var idx = 0
|
|
var dest_column = 0
|
|
while idx < cols:
|
|
if idx in empty_columns:
|
|
idx += 1
|
|
continue
|
|
|
|
for row in range(rows):
|
|
grid[row][dest_column] = grid[row][idx]
|
|
idx += 1
|
|
dest_column += 1
|
|
|
|
|
|
|
|
redraw_grid()
|
|
calculate_token_groups()
|
|
|
|
func redraw_grid():
|
|
for row in range(rows):
|
|
for column in range(cols):
|
|
var current_token = grid[row][column]
|
|
if current_token == null:
|
|
continue
|
|
|
|
current_token.set_debug_label(str(row) + "," + str(column))
|
|
|
|
current_token.position = Vector2(offset*column, offset*row)
|
|
|
|
|
|
|
|
func calculate_token_groups():
|
|
groups = []
|
|
var visited_nodes = []
|
|
var group_queue = []
|
|
for row in rows:
|
|
for col in cols:
|
|
if [row, col] in visited_nodes or grid[row][col] == null:
|
|
continue
|
|
|
|
group_queue.append([row,col])
|
|
|
|
var new_group = []
|
|
while not group_queue.is_empty():
|
|
var current_coord = group_queue.pop_back()
|
|
var current_token = grid[current_coord[0]][current_coord[1]]
|
|
new_group.append(current_coord)
|
|
visited_nodes.append(current_coord)
|
|
|
|
var adjacent_token_coords = [
|
|
[current_coord[0] - 1, current_coord[1]],
|
|
[current_coord[0], current_coord[1] + 1],
|
|
[current_coord[0] + 1, current_coord[1]],
|
|
[current_coord[0], current_coord[1] - 1]
|
|
]
|
|
|
|
var valid_coords = adjacent_token_coords.filter(
|
|
func(coord_pair):
|
|
return (
|
|
coord_pair[0] >= 0 and
|
|
coord_pair[0] < rows and
|
|
coord_pair[1] >= 0 and
|
|
coord_pair[1] < cols
|
|
)
|
|
)
|
|
|
|
for coord in valid_coords:
|
|
var token = grid[coord[0]][coord[1]]
|
|
if (token != null and
|
|
coord not in visited_nodes and
|
|
grid[coord[0]][coord[1]].type == current_token.type and
|
|
coord not in group_queue):
|
|
group_queue.append(coord)
|
|
groups.append(new_group)
|
|
|
|
debug_label.text = str(groups)
|
|
|
|
func get_group_of_token(token_coord) -> Array:
|
|
for group in groups:
|
|
if token_coord in group:
|
|
return group
|
|
|
|
return []
|
|
|
|
|
|
func _on_boundary_area_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
|
|
if event.is_action_pressed("select"):
|
|
var position = self.get_local_mouse_position()
|
|
var token_coord = pixel_to_grid_coord(position)
|
|
var group = get_group_of_token(token_coord)
|
|
if group.size() >= min_group_size:
|
|
for coord in group:
|
|
var current_token = grid[coord[0]][coord[1]] as Token
|
|
current_token.queue_free()
|
|
grid[coord[0]][coord[1]] = null # do I actually want a null value or should there be some other placeholder?
|
|
|
|
update_grid()
|