Many changes

Handle it
This commit is contained in:
Dan Baker 2025-05-04 09:30:14 +01:00
parent bf09402bc5
commit 214e0aa5e0
366 changed files with 24353 additions and 2096 deletions

View file

@ -4,7 +4,7 @@ func _ready() -> void:
Log.pr("CoordUtility ready")
func all_cells(start : Vector2i, end : Vector2i) -> Array:
func all_cells(start: Vector2i, end: Vector2i) -> Array:
# Returns all cells between start and end
var cells = []
@ -21,7 +21,6 @@ func perimeter_cells(start: Vector2i, end: Vector2i, inclusive: bool = true, wid
# Returns cells on the perimeter between start and end
# inclusive: if true, includes the area cells, if false, excludes them
# width: the thickness of the perimeter (default: 1)
var cells: Array[Vector2i] = []
var min_x: int = min(start.x, end.x)
var max_x: int = max(start.x, end.x)
@ -39,6 +38,7 @@ func perimeter_cells(start: Vector2i, end: Vector2i, inclusive: bool = true, wid
var outer_max_y: int
if inclusive:
Log.pr("Drawing within bounds of the original rectangle")
# For inclusive, inner bounds are the original rectangle
inner_min_x = min_x
inner_min_y = min_y
@ -51,6 +51,7 @@ func perimeter_cells(start: Vector2i, end: Vector2i, inclusive: bool = true, wid
outer_max_x = max_x + (width - 1)
outer_max_y = max_y + (width - 1)
else:
Log.pr("Drawing outside bounds of the original rectangle")
# For exclusive, inner bounds are the original rectangle
inner_min_x = min_x
inner_min_y = min_y
@ -77,4 +78,21 @@ func perimeter_cells(start: Vector2i, end: Vector2i, inclusive: bool = true, wid
if x < inner_min_x or x > inner_max_x or y < inner_min_y or y > inner_max_y:
cells.append(pos)
return cells
return cells
func get_surrounding_tiles(given_tile: Vector2i, spread: int = 1) -> Array[Vector2i]:
Log.pr("Getting surrounding tiles for tile: ", given_tile, " with spread: ", spread)
var surrounding_tiles: Array[Vector2i] = []
# Loop from -spread to +spread in both directions
for y in range(-spread, spread + 1):
for x in range(-spread, spread + 1):
# Skip the center tile if you don't want it included
if x == 0 and y == 0:
continue
var target_tile = given_tile + Vector2i(x, y)
surrounding_tiles.append(target_tile)
Log.pr("Surrounding tiles: ", surrounding_tiles)
return surrounding_tiles

14
utility/Globals.gd Normal file
View file

@ -0,0 +1,14 @@
extends Node
class_name GlobalVariables
const TILE_SIZE = 32
const ROOM_WIDTH = 20
const ROOM_HEIGHT = 16
const GRID_WIDTH = 4
const GRID_HEIGHT = 4
const MAP_EMPTY = 0
const MAP_PATH = 1
const MAP_START = 2
const MAP_FINISH = 4
const MAP_UP_CELL = 3

1
utility/Globals.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://gf47g1mgttf5

86
utility/MapBuilder.gd Normal file
View file

@ -0,0 +1,86 @@
extends Node
class_name MapBuilderClass
# Function to copy a TileMap layer from one scene to a target TileMap at a specific grid position
func copy_tilemap_to_target(source_scene, target_tilemap: TileMapLayer, target_layer: String, grid_position: Vector2i):
# First, load and instantiate the source scene if it's a resource path
Log.pr("Copying tilemap from source scene to target tilemap at grid position: ", grid_position)
Log.pr("Source scene: ", source_scene)
var source_instance
if source_scene is String:
source_instance = load(source_scene).instantiate()
elif source_scene is PackedScene:
Log.pr("Source scene is a PackedScene, instantiating it")
source_instance = source_scene.instantiate()
else:
source_instance = source_scene
# Find the source TileMap in the loaded scene
var source_tilemap = find_tilemap_by_name(source_instance, target_layer)
if not source_tilemap:
push_error("Could not find TileMapLayer in source scene", source_tilemap)
if source_instance is Node and source_instance.is_inside_tree():
source_instance.queue_free()
return
# Get the size of the source room in tiles
var source_used_cells = source_tilemap.get_used_cells() # 0 is the layer index
if source_used_cells.size() == 0:
push_warning("Source TileMapLayer has no cells")
if source_instance is Node and source_instance.is_inside_tree():
source_instance.queue_free()
return
# Calculate the offset for placement in the target grid
var offset_x = grid_position.x * Global.ROOM_WIDTH
var offset_y = grid_position.y * Global.ROOM_HEIGHT
# Copy cells from source to target with proper offset
for cell in source_used_cells:
var target_cell = Vector2i(cell.x + offset_x, cell.y + offset_y)
# Get the tile data from source
#var source_tile_data = source_tilemap.get_cell_tile_data(cell)
var source_atlas_coords = source_tilemap.get_cell_atlas_coords(cell)
var source_alternative_tile = source_tilemap.get_cell_alternative_tile(cell)
# Set the same tile in the target TileMap
target_tilemap.set_cell(target_cell, source_tilemap.get_cell_source_id(cell), source_atlas_coords, source_alternative_tile)
# Clean up the source instance if we instantiated it
if source_instance is Node and source_instance.is_inside_tree():
source_instance.queue_free()
# Helper function to find a TileMap by name in a scene
func find_tilemap_by_name(root_node: Node, tilemap_name: String) -> TileMapLayer:
if root_node is TileMapLayer and root_node.name == tilemap_name:
return root_node
for child in root_node.get_children():
var result = find_tilemap_by_name(child, tilemap_name)
if result:
return result
return null
func redraw_terrain(positions: Array, layer: TileMapLayer, terrain_set: int, terrain: int) -> void:
Log.pr("Filtering and redrawing surrounding tiles", positions)
# Filter positions to only include cells with terrainset 0 and terrain 0
var filtered_positions: Array = []
for cell in positions:
var tile_data = layer.get_cell_tile_data(cell)
if tile_data and tile_data.get_terrain_set() == terrain_set and tile_data.get_terrain() == terrain:
filtered_positions.append(cell)
# Only redraw if we have filtered cells
if filtered_positions.size() > 0:
Log.pr("Redrawing filtered tiles:", filtered_positions)
layer.set_cells_terrain_connect(filtered_positions, terrain_set, terrain)
else:
Log.pr("No tiles to redraw after filtering")

View file

@ -0,0 +1 @@
uid://cuyp1adhi86bs

View file

@ -2,157 +2,157 @@ extends Node
class_name MapGenerator
# Map constants
const GRID_WIDTH = 4
const GRID_HEIGHT = 4
const EMPTY = 0
const PATH = 1
const START = 2
const FINISH = 4
const UP_CELL = 3
var GRID_WIDTH = Global.GRID_WIDTH
var GRID_HEIGHT = Global.GRID_HEIGHT
var EMPTY = Global.MAP_EMPTY
var PATH = Global.MAP_PATH
var START = Global.MAP_START
var FINISH = Global.MAP_FINISH
var UP_CELL = Global.MAP_UP_CELL
# Map generation parameters
var up_probability_base = 0.1 # Base probability to move up
var up_probability_increase = 0.2 # How much the probability increases each time we stay on the same row
var up_probability_base = 0.1 # Base probability to move up
var up_probability_increase = 0.2 # How much the probability increases each time we stay on the same row
# The map grid
var map = []
func generate_map():
# Initialize map with empty cells
map = []
for y in range(GRID_HEIGHT):
var row = []
for x in range(GRID_WIDTH):
row.append(EMPTY)
map.append(row)
# Pick a starting location in the bottom row
var current_x = randi() % GRID_WIDTH
var current_y = GRID_HEIGHT - 1
# Mark as start
map[current_y][current_x] = START
# Track visited cells to avoid loops
var visited = {}
visited[Vector2(current_x, current_y)] = true
# Path generation
var final_position = generate_path(current_x, current_y, visited)
# Set finish cell in top row and connect path to it
connect_to_finish(final_position.x, final_position.y, visited)
# Initialize map with empty cells
map = []
for y in range(GRID_HEIGHT):
var row = []
for x in range(GRID_WIDTH):
row.append(EMPTY)
map.append(row)
# Pick a starting location in the bottom row
var current_x = RNG.randi() % GRID_WIDTH
var current_y = GRID_HEIGHT - 1
# Mark as start
map[current_y][current_x] = START
# Track visited cells to avoid loops
var visited = {}
visited[Vector2(current_x, current_y)] = true
# Path generation
var final_position = generate_path(current_x, current_y, visited)
# Set finish cell in top row and connect path to it
connect_to_finish(final_position.x, final_position.y, visited)
# Generate path from start to top row, return final position
func generate_path(current_x, current_y, visited):
var up_probability = up_probability_base
while current_y > 0: # Continue until we reach the top row
# Try to move left or right until we can't proceed further
var can_move_horizontal = true
while can_move_horizontal:
# Decide whether to try moving up
if randf() < up_probability:
# We'll try moving up
break
# Increase probability for next time
up_probability += up_probability_increase
# Choose direction randomly (left or right)
var direction = 1 if randf() > 0.5 else -1
var new_x = current_x + direction
# Check if we can move in that direction
if new_x >= 0 and new_x < GRID_WIDTH and not Vector2(new_x, current_y) in visited:
current_x = new_x
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
else:
# Try the other direction
direction = -direction
new_x = current_x + direction
if new_x >= 0 and new_x < GRID_WIDTH and not Vector2(new_x, current_y) in visited:
current_x = new_x
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
else:
# Can't move horizontally anymore
can_move_horizontal = false
# Mark current cell as an UP_CELL before moving up
map[current_y][current_x] = UP_CELL
# Move up
current_y -= 1
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
# Reset up probability since we've moved up
up_probability = up_probability_base
# Return the final position (on the top row)
return Vector2(current_x, current_y)
var up_probability = up_probability_base
while current_y > 0: # Continue until we reach the top row
# Try to move left or right until we can't proceed further
var can_move_horizontal = true
while can_move_horizontal:
# Decide whether to try moving up
if RNG.randf() < up_probability:
# We'll try moving up
break
# Increase probability for next time
up_probability += up_probability_increase
# Choose direction randomly (left or right)
var direction = 1 if RNG.randf() > 0.5 else -1
var new_x = current_x + direction
# Check if we can move in that direction
if new_x >= 0 and new_x < GRID_WIDTH and not Vector2(new_x, current_y) in visited:
current_x = new_x
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
else:
# Try the other direction
direction = - direction
new_x = current_x + direction
if new_x >= 0 and new_x < GRID_WIDTH and not Vector2(new_x, current_y) in visited:
current_x = new_x
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
else:
# Can't move horizontally anymore
can_move_horizontal = false
# Mark current cell as an UP_CELL before moving up
map[current_y][current_x] = UP_CELL
# Move up
current_y -= 1
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
# Reset up probability since we've moved up
up_probability = up_probability_base
# Return the final position (on the top row)
return Vector2(current_x, current_y)
# Connect the path to a finish point in the top row
func connect_to_finish(current_x, current_y, visited):
# Choose a finish position
var finish_x = randi() % GRID_WIDTH
# If we randomly picked the current position, we're done
if finish_x == current_x:
map[current_y][current_x] = FINISH
return
# Otherwise, create a path to the finish
var direction = 1 if finish_x > current_x else -1
# Move horizontally toward the finish position
while current_x != finish_x:
current_x += direction
# If we've already visited this cell, we have a loop - break and place finish here
if Vector2(current_x, current_y) in visited:
break
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
# Place finish at the final position
map[current_y][current_x] = FINISH
# Choose a finish position
var finish_x = RNG.randi() % GRID_WIDTH
# If we randomly picked the current position, we're done
if finish_x == current_x:
map[current_y][current_x] = FINISH
return
# Otherwise, create a path to the finish
var direction = 1 if finish_x > current_x else -1
# Move horizontally toward the finish position
while current_x != finish_x:
current_x += direction
# If we've already visited this cell, we have a loop - break and place finish here
if Vector2(current_x, current_y) in visited:
break
map[current_y][current_x] = PATH
visited[Vector2(current_x, current_y)] = true
# Place finish at the final position
map[current_y][current_x] = FINISH
func print_map():
print("Generated Map:")
print("- Legend: 0=Empty, 1=Path, 2=Start, 4=Finish, 3=MoveUp")
print("")
var visual_map = ""
for y in range(GRID_HEIGHT):
var row_str = ""
for x in range(GRID_WIDTH):
var cell_value = map[y][x]
match cell_value:
EMPTY: row_str += "[ ] "
PATH: row_str += "[•] "
START: row_str += "[S] "
FINISH: row_str += "[F] "
UP_CELL: row_str += "[↑] "
visual_map += row_str + "\n"
print(visual_map)
# Also print as numerical grid
visual_map = ""
for y in range(GRID_HEIGHT):
var row_str = ""
for x in range(GRID_WIDTH):
row_str += str(map[y][x]) + " "
visual_map += row_str + "\n"
print(visual_map)
print("Generated Map:")
print("- Legend: 0=Empty, 1=Path, 2=Start, 4=Finish, 3=MoveUp")
print("")
var visual_map = ""
for y in range(GRID_HEIGHT):
var row_str = ""
for x in range(GRID_WIDTH):
var cell_value = map[y][x]
match cell_value:
EMPTY: row_str += "[ ] "
PATH: row_str += "[•] "
START: row_str += "[S] "
FINISH: row_str += "[F] "
UP_CELL: row_str += "[↑] "
visual_map += row_str + "\n"
print(visual_map)
# Also print as numerical grid
visual_map = ""
for y in range(GRID_HEIGHT):
var row_str = ""
for x in range(GRID_WIDTH):
row_str += str(map[y][x]) + " "
visual_map += row_str + "\n"
print(visual_map)
func get_map():
return map
return map

59
utility/RngUtility.gd Normal file
View file

@ -0,0 +1,59 @@
# file: global_rng.gd
extends Node
class_name RngUtility
# Underlying RandomNumberGenerator
var _rng: RandomNumberGenerator
func _ready():
_rng = RandomNumberGenerator.new()
randomize()
print("Global RNG initialized with seed: ", _rng.seed)
# Set a specific seed for reproducible results
func set_seed(seed_value: int) -> void:
_rng.seed = seed_value
print("RNG seed set to: ", seed_value)
# Randomize the seed (for non-reproducible results)
func randomize() -> void:
_rng.randomize()
print("RNG seed randomized to: ", _rng.seed)
# Get the current seed value
func get_seed() -> int:
return _rng.seed
# Get a random integer between min and max (inclusive)
func randi_range(min_value: int, max_value: int) -> int:
return _rng.randi_range(min_value, max_value)
# Get a random float between 0.0 and 1.0
func randf() -> float:
return _rng.randf()
func randi() -> int:
return _rng.randi()
# Get a random float between min and max
func randf_range(min_value: float, max_value: float) -> float:
return _rng.randf_range(min_value, max_value)
# Get a random normalized vector
func random_unit_vector() -> Vector2:
return Vector2(randf_range(-1.0, 1.0), randf_range(-1.0, 1.0)).normalized()
# Get a random point inside a circle with radius 1
func random_point_in_circle() -> Vector2:
var r = sqrt(randf())
var theta = randf() * 2.0 * PI
return Vector2(r * cos(theta), r * sin(theta))
# Get a random point inside a circle with specified radius
func random_point_in_circle_with_radius(radius: float) -> Vector2:
return random_point_in_circle() * radius
# Get a random boolean value with specified probability
func random_bool(probability: float = 0.5) -> bool:
return randf() < probability

View file

@ -0,0 +1 @@
uid://b8ita2lyak2o3

69
utility/SceneSelector.gd Normal file
View file

@ -0,0 +1,69 @@
extends Node
class_name SceneSelectorUtility
# Cache of scene paths
var _scene_paths_cache = {}
# Cache of loaded scenes (only populated if preload_scenes is true)
var _loaded_scenes_cache = {}
# Initialize the cache for a specific folder
func initialize_cache(folder_path: String, preload_scenes: bool = false):
if _scene_paths_cache.has(folder_path):
return # Already cached
var dir = DirAccess.open(folder_path)
if not dir:
push_error("Error: Could not open directory: " + folder_path)
return
var scene_files = []
# List all scene files
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if file_name.ends_with(".tscn"):
scene_files.append(folder_path + "/" + file_name)
file_name = dir.get_next()
Log.pr("Found %d scene files in %s" % [scene_files.size(), folder_path])
# Store in cache
_scene_paths_cache[folder_path] = scene_files
# Optionally preload all scenes
if preload_scenes and scene_files.size() > 0:
_loaded_scenes_cache[folder_path] = []
for scene_path in scene_files:
Log.pr("Preloading scene: " + scene_path)
# Load the scene and store it in the cache
#var loaded_scene = preload(scene_path)
_loaded_scenes_cache[folder_path].append(load(scene_path))
# Get a random scene from a folder (using caches)
func get_random_scene(folder_path: String):
# Make sure the cache is initialized
if not _scene_paths_cache.has(folder_path):
Log.pr("Initializing cache for folder: " + folder_path)
initialize_cache(folder_path, true)
var scene_paths = _scene_paths_cache[folder_path]
if scene_paths.size() == 0:
push_error("No scene files found in directory: " + folder_path)
return null
# Get random index
var random_index = RNG.randi_range(0, scene_paths.size() - 1)
# Return from loaded scenes cache if available
if _loaded_scenes_cache.has(folder_path):
Log.pr("Returning preloaded scene from cache")
return _loaded_scenes_cache[folder_path][random_index]
# Otherwise load the scene
var scene = load(scene_paths[random_index])
Log.pr(scene)
return scene

View file

@ -0,0 +1 @@
uid://cs18x6clkepoa