project organization
This commit is contained in:
24
components/grid.tscn
Normal file
24
components/grid.tscn
Normal file
@@ -0,0 +1,24 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bnfois00347c2"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c1k5pgejmn3bb" path="res://components/scripts/grid.gd" id="1_ebq2e"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ebq2e"]
|
||||
resource_local_to_scene = true
|
||||
|
||||
[node name="Grid" type="Node2D"]
|
||||
script = ExtResource("1_ebq2e")
|
||||
offset = 60.0
|
||||
|
||||
[node name="BoundaryArea" type="Area2D" parent="."]
|
||||
|
||||
[node name="BoundaryShape" type="CollisionShape2D" parent="BoundaryArea"]
|
||||
shape = SubResource("RectangleShape2D_ebq2e")
|
||||
|
||||
[node name="Debug Label" type="Label" parent="."]
|
||||
offset_left = -372.0
|
||||
offset_top = -206.0
|
||||
offset_right = 729.0
|
||||
offset_bottom = -123.0
|
||||
autowrap_mode = 1
|
||||
|
||||
[connection signal="input_event" from="BoundaryArea" to="." method="_on_boundary_area_input_event"]
|
||||
238
components/scripts/grid.gd
Normal file
238
components/scripts/grid.gd
Normal file
@@ -0,0 +1,238 @@
|
||||
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://components/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 column in cols:
|
||||
grid.append([])
|
||||
for row in rows:
|
||||
grid[column].append(null)
|
||||
|
||||
generate_board()
|
||||
|
||||
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 = get_token(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 get_token(row, col):
|
||||
return grid[col][row]
|
||||
|
||||
func set_token(token: Token, row, col):
|
||||
grid[col][row] = token
|
||||
|
||||
func generate_board():
|
||||
for row in rows:
|
||||
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)
|
||||
set_token(token_node, row, column)
|
||||
|
||||
func highlight_group(group: Array, enable: bool):
|
||||
|
||||
for coord in group:
|
||||
var current_token = get_token(coord[0], coord[1])
|
||||
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
|
||||
var temp_col
|
||||
for col in range(cols):
|
||||
temp_col = grid[col].filter(func(token): return token != null)
|
||||
for idx in range(rows - temp_col.size()):
|
||||
set_token(null, idx, col)
|
||||
for idx in range(temp_col.size()):
|
||||
set_token(temp_col[idx], rows - temp_col.size() + idx, col)
|
||||
|
||||
# search for empty columns and compact horizontally
|
||||
var temp_grid = grid.filter(func(col: Array): return !col.all(func(token): return token == null))
|
||||
|
||||
var arr = []
|
||||
arr.resize(rows)
|
||||
arr.fill(null)
|
||||
for _i in range(cols - temp_grid.size()):
|
||||
temp_grid.append(arr)
|
||||
|
||||
grid = temp_grid
|
||||
|
||||
|
||||
redraw_grid()
|
||||
calculate_token_groups()
|
||||
|
||||
#func donot():
|
||||
#for col 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])
|
||||
#
|
||||
## 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 = get_token(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 get_token(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 = get_token(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 = get_token(coord[0],coord[1])
|
||||
if (token != null and
|
||||
coord not in visited_nodes and
|
||||
token.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 = get_token(coord[0], coord[1])
|
||||
current_token.queue_free()
|
||||
set_token(null, coord[0], coord[1])# do I actually want a null value or should there be some other placeholder?
|
||||
|
||||
update_grid()
|
||||
1
components/scripts/grid.gd.uid
Normal file
1
components/scripts/grid.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c1k5pgejmn3bb
|
||||
41
components/scripts/token.gd
Normal file
41
components/scripts/token.gd
Normal file
@@ -0,0 +1,41 @@
|
||||
extends Node2D
|
||||
class_name Token
|
||||
|
||||
enum token_type {TYPE_1, TYPE_2, TYPE_3, TYPE_4}
|
||||
enum token_state {NONE, HIGHLIGHT}
|
||||
|
||||
var type: token_type = token_type.TYPE_1
|
||||
var state: token_state = token_state.NONE
|
||||
|
||||
var color_polygon: Polygon2D
|
||||
var highlight_polygon: Polygon2D
|
||||
var debug_label: Label
|
||||
|
||||
func _ready():
|
||||
color_polygon = $Color
|
||||
highlight_polygon = $highlight_indicator
|
||||
debug_label = $"Debug Label"
|
||||
|
||||
func set_type(type: token_type):
|
||||
self.type = type
|
||||
match self.type:
|
||||
token_type.TYPE_1:
|
||||
color_polygon.color = Color.RED
|
||||
token_type.TYPE_2:
|
||||
color_polygon.color = Color.GREEN
|
||||
token_type.TYPE_3:
|
||||
color_polygon.color = Color.BLUE
|
||||
token_type.TYPE_4:
|
||||
color_polygon.color = Color.GOLD
|
||||
|
||||
func set_debug_label(text: String):
|
||||
debug_label.text = text
|
||||
|
||||
|
||||
func set_highlighted(highlight: bool):
|
||||
state = token_state.HIGHLIGHT if highlight else token_state.NONE
|
||||
match state:
|
||||
token_state.HIGHLIGHT:
|
||||
highlight_polygon.visible = true
|
||||
token_state.NONE:
|
||||
highlight_polygon.visible = false
|
||||
1
components/scripts/token.gd.uid
Normal file
1
components/scripts/token.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cy18iue2caocn
|
||||
44
components/token.tscn
Normal file
44
components/token.tscn
Normal file
@@ -0,0 +1,44 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://b50otusq306jl"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cy18iue2caocn" path="res://components/scripts/token.gd" id="1_mep5p"]
|
||||
[ext_resource type="Texture2D" uid="uid://cqtw7t2uag6f8" path="res://icon.svg" id="2_lcbe8"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_0ucay"]
|
||||
outline_size = 2
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_bd72f"]
|
||||
blend_mode = 1
|
||||
|
||||
[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_0ucay"]
|
||||
blend_mode = 2
|
||||
|
||||
[node name="Token" type="Node2D"]
|
||||
script = ExtResource("1_mep5p")
|
||||
|
||||
[node name="Debug Label" type="Label" parent="."]
|
||||
z_index = 2
|
||||
offset_left = 6.0
|
||||
offset_top = 3.0
|
||||
offset_right = 39.0
|
||||
offset_bottom = 41.0
|
||||
text = "1,1"
|
||||
label_settings = SubResource("LabelSettings_0ucay")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
scale = Vector2(0.4, 0.4)
|
||||
texture = ExtResource("2_lcbe8")
|
||||
centered = false
|
||||
|
||||
[node name="Color" type="Polygon2D" parent="."]
|
||||
material = SubResource("CanvasItemMaterial_bd72f")
|
||||
position = Vector2(6, 6)
|
||||
color = Color(0.84101, 0.000705212, 0.866408, 1)
|
||||
polygon = PackedVector2Array(0, 0, 40, 0, 40, 40, 0, 40)
|
||||
|
||||
[node name="highlight_indicator" type="Polygon2D" parent="."]
|
||||
material = SubResource("CanvasItemMaterial_0ucay")
|
||||
position = Vector2(52.8333, 76.6667)
|
||||
scale = Vector2(0.427083, 0.319444)
|
||||
polygon = PackedVector2Array(-112, -96, -16, -96, -64, -168)
|
||||
uv = PackedVector2Array(-112, -96, -16, -96, -72, -160)
|
||||
Reference in New Issue
Block a user