Implements basic flood fill verification for selection

This commit is contained in:
effie 2025-06-28 15:54:07 +10:00
parent 04ea9c0be2
commit ea31a0363b
10 changed files with 271 additions and 208 deletions

View File

@ -6,16 +6,41 @@
[node name="CanvasLayer" type="CanvasLayer" parent="."] [node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="CheckButton" type="CheckButton" parent="CanvasLayer"] [node name="SelectToggle" type="CheckButton" parent="CanvasLayer"]
offset_left = 1008.0 offset_left = 1008.0
offset_top = 18.0 offset_top = 18.0
offset_right = 1120.0 offset_right = 1120.0
offset_bottom = 49.0 offset_bottom = 49.0
text = "Building" text = "Building"
[node name="BuildButton" type="Button" parent="CanvasLayer"]
offset_left = 1033.0
offset_top = 59.0
offset_right = 1081.0
offset_bottom = 90.0
text = "Build"
[node name="DestroyButton" type="Button" parent="CanvasLayer"]
offset_left = 1031.0
offset_top = 105.0
offset_right = 1079.0
offset_bottom = 136.0
text = "Destroy
"
[node name="CancelButton" type="Button" parent="CanvasLayer"]
offset_left = 1031.0
offset_top = 145.0
offset_right = 1091.0
offset_bottom = 176.0
text = "Cancel"
[node name="MapManager" parent="." instance=ExtResource("1_ig7tw")] [node name="MapManager" parent="." instance=ExtResource("1_ig7tw")]
[node name="Camera3D" type="Camera3D" parent="."] [node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 18.064, 14.45, 9.456) transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 16.504, 23.621, 15.103)
[connection signal="toggled" from="CanvasLayer/CheckButton" to="MapManager" method="_build_toggled"] [connection signal="toggled" from="CanvasLayer/SelectToggle" to="MapManager" method="_build_toggled"]
[connection signal="pressed" from="CanvasLayer/BuildButton" to="MapManager" method="_on_build_button_pressed"]
[connection signal="pressed" from="CanvasLayer/DestroyButton" to="MapManager" method="_on_destroy_button_pressed"]
[connection signal="pressed" from="CanvasLayer/CancelButton" to="MapManager" method="_on_cancel_button_pressed"]

View File

@ -1,235 +1,197 @@
extends Node3D extends Node3D
var gridsize = 32
var astar_grid_room = AStarGrid2D.new()
var load_tile = preload("res://tiles/base_tile/tile.tscn") var load_tile = preload("res://tiles/base_tile/tile.tscn")
var tile_drag_dict = {} var tile_dict = {}
var tile_drag_array_global = []
var selection_drag_dict = {}
var selection_dict = {}
var tile_count_x_hist = null var tile_count_x_hist = null
var tile_count_z_hist = null var tile_count_z_hist = null
var tile_drag_x_hist = null var build_forbidden = false
var tile_drag_z_hist = null
func _ready(): func _ready():
pass
# Sets up a simple 2D grid of blank tiles.
for x in range(gridsize):
for z in range (gridsize):
var pos = Vector3i(x + 0.5,0 ,z + 0.5)
var tile = load_tile.instantiate()
tile.set_position(pos)
tile.type = 0
tile_dict[pos] = tile
add_child(tile)
func build_selection(b):
if build_forbidden:
print("No fucking building aaaaaa")
return
# When the build or destroy button is clicked, changes the selected tiles to match the button's request
for i in selection_dict:
var tile_selected = tile_dict[i]
tile_selected.build_this_tile(b)
selection_dict.clear()
for i in tile_dict:
if not selection_dict.has(i):
var tile_selected = tile_dict[i]
tile_selected.select_this_tile(false)
func clear_selection():
# When the clear button is clicked, it clears the selected tiles without doing anything.
for i in tile_dict:
var tile_selected = tile_dict[i]
tile_selected.select_this_tile(false)
selection_dict.clear()
func end_select_drag():
# Locks in the dragged tiles on mouse-up
func clear_build_drag():
tile_count_x_hist = 0 tile_count_x_hist = 0
tile_count_z_hist = 0 tile_count_z_hist = 0
selection_dict.merge(selection_drag_dict)
tile_drag_x_hist = 0 if not verify_room():
tile_drag_z_hist = 0 build_forbidden = true
for i in tile_drag_dict:
var tile = tile_drag_dict[i]
tile.queue_free()
tile_drag_dict.clear()
selection_drag_dict.clear()
func draw_tile_click(start_pos): func draw_tile_click(start_pos):
var build_start_pos: Vector3i = start_pos.snapped(Vector3i(1, 1, 1)) var build_start_pos: Vector3i = start_pos.snapped(Vector3i(1, 1, 1))
tile_drag_x_hist = 0 tile_count_x_hist = 0
tile_drag_z_hist = 0 tile_count_z_hist = 0
var tile = load_tile.instantiate() select_tile(build_start_pos)
tile.position = build_start_pos
tile_drag_dict[build_start_pos] = tile func init_select_drag(float_build_start_pos, float_build_mouse_pos):
add_child(tile) var select_drag_array = []
func init_tile_drag(float_build_start_pos, float_build_mouse_pos):
var tile_drag_array = []
var build_start_pos: Vector3i = float_build_start_pos.snapped(Vector3i(1.0, 1.0, 1.0)) var build_start_pos: Vector3i = float_build_start_pos.snapped(Vector3i(1.0, 1.0, 1.0))
var build_mouse_pos: Vector3i = float_build_mouse_pos.snapped(Vector3i(1.0, 1.0, 1.0)) var build_mouse_pos: Vector3i = float_build_mouse_pos.snapped(Vector3i(1.0, 1.0, 1.0))
var tile_count_x = build_mouse_pos.x - build_start_pos.x var tile_count_x = build_mouse_pos.x - build_start_pos.x
var tile_count_z = build_mouse_pos.z - build_start_pos.z var tile_count_z = build_mouse_pos.z - build_start_pos.z
if not tile_count_x_hist == tile_count_x or not tile_count_z_hist == tile_count_z: if not tile_count_x_hist == tile_count_x or not tile_count_z_hist == tile_count_z:
var tile_count_x_diff = tile_count_x_hist - tile_count_x
var tile_count_z_diff = tile_count_z_hist - tile_count_z
tile_count_x_hist = tile_count_x tile_count_x_hist = tile_count_x
tile_count_z_hist = tile_count_z tile_count_z_hist = tile_count_z
for x in range(min(0, tile_count_x), max(0, tile_count_x) + 1): for x in range(min(0, tile_count_x), max(0, tile_count_x) + 1):
for z in range(min(0, tile_count_z), max(0, tile_count_z) + 1): for z in range(min(0, tile_count_z), max(0, tile_count_z) + 1):
var tile_drag_pos = build_start_pos + Vector3i(x, 0, z) var select_drag_pos = build_start_pos + Vector3i(x, 0, z)
tile_drag_array.append(tile_drag_pos) select_drag_array.append(select_drag_pos)
draw_select_drag(select_drag_array)
draw_tile_drag(tile_drag_array) func draw_select_drag(array):
selection_drag_dict.clear()
func draw_tile_drag(array): for i in tile_dict:
if not selection_dict.has(i):
tile_drag_dict.clear() var tile_selected = tile_dict[i]
tile_selected.select_this_tile(false)
for i in self.get_children():
i.queue_free()
for i in array: for i in array:
var id = i var id = i
select_tile(id)
if not tile_drag_dict.has(id):
var tile = load_tile.instantiate()
tile.position = i
tile_drag_dict[id] = tile
add_child(tile)
#tile_drag_x_hist = x_diff + tile_drag_x_hist func select_tile(pos):
#tile_drag_z_hist = z_diff + tile_drag_z_hist
# if tile_dict.has(pos):
#if x_diff:
#for z in range(min(0, tile_drag_z_hist), max(0, tile_drag_z_hist) + 1): var tile = tile_dict[pos]
#for x in abs(x_diff):
#var id = Vector3i(start_pos.x - tile_drag_x_hist, 0, start_pos.z - z)
##var lastid = Vector3i(start_pos.x - tile_drag_x_hist - x_diff, 0, start_pos.z - z)
#if tile_drag_dict.has(id):
#var tile = tile_drag_dict[id]
#tile.queue_free()
#tile_drag_dict.erase(id)
#else:
#
#var tile = load_tile.instantiate()
#tile.position = id
#tile_drag_dict[id] = tile
#add_child(tile)
#
#if z_diff:
#for x in range(min(0, tile_drag_x_hist), max(0, tile_drag_x_hist) + 1):
#for z in abs(z_diff):
#var id = Vector3i(start_pos.x - x, 0, start_pos.z - tile_drag_z_hist)
#
#if tile_drag_dict.has(id):
#var tile = tile_drag_dict[id]
#tile.queue_free()
#tile_drag_dict.erase(id)
#else:
#var tile = load_tile.instantiate()
#tile.position = id
#tile_drag_dict[id] = tile
#add_child(tile)
#print(tile_drag_dict)
#if x_diff > 0:
#var tile = load_tile.instantiate()
#tile.position = Vector3i(start_pos.x - tile_drag_x_hist, 0, tile_drag_z_hist - z)
#
#print(Vector3i(start_pos.x - tile_drag_x_hist, 0, tile_drag_z_hist - z))
#tile_drag_dict[tile.position] = tile
#
#add_child(tile)
#
#if x_diff < 0:
#print(Vector3i(start_pos.x - tile_drag_x_hist, 0, tile_drag_z_hist - z))
tile.select_this_tile(true)
#print(tile_drag_z_hist)
# order of events:
# get start and current mouse pos
# check for changes in drag grid dimension
# if changes, send to gird draw func
# add/remove tiles along each changed dimension
#var tile_x_diff = null
#var tile_z_diff = null
#
#
#
#if tile_count_x_hist == null:
#tile_x_diff = 0
#else:
#tile_x_diff = tile_count_x_hist - tile_count_x
#
#tile_count_x_hist = tile_x_diff
##print(tile_count_x_hist)
#
#if not tile_count_z_hist:
#tile_z_diff = 0
#else:
#tile_z_diff = tile_count_z_hist - tile_count_z
#
#if tile_x_diff or tile_z_diff:
#draw_tile_drag(tile_x_diff, tile_z_diff, build_start_pos)
#tile_count_x_hist = tile_count_x
#tile_count_z_hist = tile_count_z
#var tile_drag_array = []
#var tile_count_x_array = [0]
#var tile_count_z_array = [0]
#
#var tile_count_x = build_mouse_pos.x - build_start_pos.x
#var tile_count_z = build_mouse_pos.z - build_start_pos.z
#if tile_count_x < 0:
#tile_count_x_array.append_array(range(-1, tile_count_x - 1, -1))
#tile_count_x_array.reverse()
#
#if tile_count_x > 0:
#tile_count_x_array.append_array(range(1, tile_count_x + 1))
#
#if tile_count_z < 0:
#tile_count_z_array.append_array(range(-1, tile_count_z - 1, -1))
#tile_count_z_array.reverse()
#
#if tile_count_z > 0:
#tile_count_z_array.append_array(range(1, tile_count_z + 1))
#for x in range(min(0, tile_count_x), max(0, tile_count_x) + 1):
#for z in range(min(0, tile_count_z), max(0, tile_count_z) + 1):
#var tile_drag_pos = build_start_pos + Vector3i(x, 0, z)
#
#tile_drag_array.append(tile_drag_pos)
#for x in tile_count_x_array:
#for z in tile_count_z_array:
#
#print(tile_drag_array)
#func draw_tile_drag(x_diff, z_diff, start_pos):
#print(x_diff, " ", z_diff)
#i
#
#tile.position = i
#
#tile_drag_dict[i] = tile
pass
#print(x_diff, " ", z_diff)
#for i in self.get_children():
#i.queue_free()
#for i in array: selection_drag_dict[pos] = tile
#
#var id = i func verify_room():
#
#if not tile_drag_dict.has(id): if selection_dict == selection_drag_dict:
#var tile = load_tile.instantiate() return true
#
#tile.position = i var verify_array = selection_dict.keys()
# var verify_queue_array = [verify_array[0]]
#tile_drag_dict[id] = tile var verify_checked_array = []
#
#add_child(tile) while verify_array:
if not verify_queue_array:
return false
var verify_pos = verify_queue_array[0]
if selection_dict.has(Vector3i(verify_pos.x + 1, 0, verify_pos.z)):
if not verify_checked_array.has(Vector3i(verify_pos.x + 1, 0, verify_pos.z)):
if not verify_queue_array.has(Vector3i(verify_pos.x + 1, 0, verify_pos.z)):
verify_queue_array.append(Vector3i(verify_pos.x + 1, 0, verify_pos.z))
if selection_dict.has(Vector3i(verify_pos.x - 1, 0, verify_pos.z)):
if not verify_checked_array.has(Vector3i(verify_pos.x - 1, 0, verify_pos.z)):
if not verify_queue_array.has(Vector3i(verify_pos.x - 1, 0, verify_pos.z)):
verify_queue_array.append(Vector3i(verify_pos.x - 1, 0, verify_pos.z))
if selection_dict.has(Vector3i(verify_pos.x, 0, verify_pos.z + 1)):
if not verify_checked_array.has(Vector3i(verify_pos.x, 0, verify_pos.z + 1)):
if not verify_queue_array.has(Vector3i(verify_pos.x, 0, verify_pos.z + 1)):
verify_queue_array.append(Vector3i(verify_pos.x, 0, verify_pos.z + 1))
if selection_dict.has(Vector3i(verify_pos.x, 0, verify_pos.z - 1)):
if not verify_checked_array.has(Vector3i(verify_pos.x, 0, verify_pos.z - 1)):
if not verify_queue_array.has(Vector3i(verify_pos.x, 0, verify_pos.z - 1)):
verify_queue_array.append(Vector3i(verify_pos.x, 0, verify_pos.z - 1))
verify_checked_array.append(verify_pos)
verify_queue_array.erase(verify_pos)
verify_array.erase(verify_pos)
return true
#if verify_dict.has(Vector3i(verify_pos.x + 1, 0, verify_pos.z)) && not verified.has(Vector3i(verify_pos.x + 1, 0, verify_pos.z)):
#verified.append(verify_pos)
#verify_pos = Vector3i(verify_pos.x + 1, 0, verify_pos.z)
#elif verify_dict.has(Vector3i(verify_pos.x - 1, 0, verify_pos.z)):
#verified.append(verify_pos)
#verify_pos = Vector3i(verify_pos.x - 1, 0, verify_pos.z)
#elif verify_dict.has(Vector3i(verify_pos.x, 0, verify_pos.z + 1)):
#verified.append(verify_pos)
#verify_pos = Vector3i(verify_pos.x, 0, verify_pos.z + 1)
#elif verify_dict.has(Vector3i(verify_pos.x, 0, verify_pos.z - 1)):
#verified.append(verify_pos)
#verify_pos = Vector3i(verify_pos.x, 0, verify_pos.z - 1)
#else:
#verify_dict.erase(verify_pos)
#if verify_dict:
#print(verify_dict)
#return false
return true
#if selection_dict.has(Vector3i(verify_pos.x + 1, 0, verify_pos.z)) or (selection_dict.has(Vector3i(verify_pos.x - 1, 0, verify_pos.z))) or (selection_dict.has(Vector3i(verify_pos.x, 0, verify_pos.z + 1))) or (selection_dict.has(Vector3i(verify_pos.x, 0, verify_pos.z - 1))):
#verify_dict.erase(verify_pos)

View File

@ -14,11 +14,11 @@ func _ready():
func _input(event): func _input(event):
pass pass
func _build_toggled(toggled_on) -> void: func _build_toggled(toggled_on):
build_enabled = toggled_on build_enabled = toggled_on
func toggle_building(event): func toggle_building(event):
is_building = event.pressed is_building = event.button_mask
func _on_area_3d_input_event(_camera, event, event_position, _normal, _shade_id): func _on_area_3d_input_event(_camera, event, event_position, _normal, _shade_id):
if event.is_action_pressed("select") && build_enabled: if event.is_action_pressed("select") && build_enabled:
@ -26,11 +26,25 @@ func _on_area_3d_input_event(_camera, event, event_position, _normal, _shade_id)
toggle_building(event) toggle_building(event)
map.draw_tile_click(build_start_pos) map.draw_tile_click(build_start_pos)
if event.button_mask && is_building: if is_building:
var build_mouse_pos = event_position if event.button_mask:
map.init_tile_drag(build_start_pos, build_mouse_pos) var build_mouse_pos = event_position
map.init_select_drag(build_start_pos, build_mouse_pos)
if not event.button_mask: if not event.button_mask:
map.clear_build_drag() toggle_building(event)
map.end_select_drag()
pass pass
func _on_cancel_button_pressed() -> void:
map.clear_selection()
func _on_build_button_pressed() -> void:
map.build_selection(true)
func _on_destroy_button_pressed() -> void:
map.build_selection(false)

View File

@ -0,0 +1,4 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://cunwv438ndyai"]
[resource]
albedo_color = Color(0.0629363, 0.460903, 0.811309, 1)

View File

@ -0,0 +1,4 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://cm5lg0k4vihh3"]
[resource]
albedo_color = Color(0.143918, 0.143918, 0.143918, 1)

View File

@ -0,0 +1,4 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://5s3s8phwidfy"]
[resource]
albedo_color = Color(0.638985, 0.806077, 0.995958, 1)

View File

@ -0,0 +1,4 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://dbfgv7cy7t7vo"]
[resource]
albedo_color = Color(1, 0.522709, 0.205897, 1)

4
tiles/base_tile/red.tres Normal file
View File

@ -0,0 +1,4 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://nkwjhj76xffi"]
[resource]
albedo_color = Color(0.996113, 0, 0.229677, 1)

View File

@ -1,6 +1,44 @@
extends Node3D extends Node3D
var id = null var id = null
var type = 2
var is_selected = false
var orange = preload("res://tiles/base_tile/orange.tres")
var gray = preload("res://tiles/base_tile/gray.tres")
var red = preload("res://tiles/base_tile/red.tres")
var blue = preload("res://tiles/base_tile/blue.tres")
var lightblue = preload("res://tiles/base_tile/lightblue.tres")
# tiles are 'buildable area' or not. non-buildable tiles are used as normal, but not chanegd by player # tiles are 'buildable area' or not. non-buildable tiles are used as normal, but not chanegd by player
# buildable are tiles need five total faces. If a face doesn't exist, it's assumed to be open space. # buildable are tiles need five total faces. If a face doesn't exist, it's assumed to be open space.
func _ready():
if type == 0:
pass
func invalid_this_tile():
pass
func select_this_tile(b):
is_selected = b
if b:
$WallMesh.set_material_override(lightblue)
$FloorMesh.set_material_override(blue)
else:
$WallMesh.set_material_override(gray)
$FloorMesh.set_material_override(null)
func build_this_tile(b):
if b:
type = 1
$WallMesh.visible = false
$FloorMesh.visible = true
else:
type = 0
$WallMesh.visible = true
$FloorMesh.visible = false

View File

@ -1,9 +1,11 @@
[gd_scene load_steps=4 format=3 uid="uid://gs6yynwvvot2"] [gd_scene load_steps=6 format=3 uid="uid://gs6yynwvvot2"]
[ext_resource type="Script" uid="uid://jqjcr7dxjnbt" path="res://tiles/base_tile/tile.gd" id="1_v7x5k"] [ext_resource type="Script" uid="uid://jqjcr7dxjnbt" path="res://tiles/base_tile/tile.gd" id="1_v7x5k"]
[ext_resource type="PlaneMesh" uid="uid://bis4hdushjnjm" path="res://tiles/base_tile/base_floor.tres" id="2_ipr02"] [ext_resource type="PlaneMesh" uid="uid://bis4hdushjnjm" path="res://tiles/base_tile/base_floor.tres" id="2_ipr02"]
[ext_resource type="Material" uid="uid://nkwjhj76xffi" path="res://tiles/base_tile/red.tres" id="3_h0a52"]
[ext_resource type="Material" uid="uid://cm5lg0k4vihh3" path="res://tiles/base_tile/gray.tres" id="3_tmpem"]
[sub_resource type="SphereMesh" id="SphereMesh_sbkyc"] [sub_resource type="BoxMesh" id="BoxMesh_sbkyc"]
[node name="Tile" type="Node3D"] [node name="Tile" type="Node3D"]
script = ExtResource("1_v7x5k") script = ExtResource("1_v7x5k")
@ -11,7 +13,9 @@ script = ExtResource("1_v7x5k")
[node name="FloorMesh" type="MeshInstance3D" parent="."] [node name="FloorMesh" type="MeshInstance3D" parent="."]
visible = false visible = false
mesh = ExtResource("2_ipr02") mesh = ExtResource("2_ipr02")
surface_material_override/0 = ExtResource("3_h0a52")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."] [node name="WallMesh" type="MeshInstance3D" parent="."]
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 0, 0, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
mesh = SubResource("SphereMesh_sbkyc") mesh = SubResource("BoxMesh_sbkyc")
surface_material_override/0 = ExtResource("3_tmpem")