Creating rectangle generator with random spaces between them

Godot Version

4.4

Question

Im writing a script to proceduraly generate random rectangles that never overlap.

I tried to prevent rects from overlapping by storing coords of all next rect’s tiles in an array and checking if at least one of those coords is in the array of all ever generated coords. Only if they all are completely new, it draws the next rect

As you can see on the image below, some rects generate correctly, and some merge

@tool
extends Node
class_name RectangleGenerator

@export var gen_seed: int = 0
@export var randomize_seed: bool = true

@export var map_dimensions: Vector2i = Vector2i(40, 40)
@export var max_room_dimensions: Vector2i = Vector2i(20, 20)
@export var min_room_dimensions: Vector2i = Vector2i(5, 5)
@export var distance_between_rectangles: int = 4
@export var total_rects: int = 4

@export var boundary_padding: int = 4
@export_tool_button("Generate Map") var map_gen_button = generate_map
@export var tilemap_layer: TileMapLayer

func _ready() -> void:
	generate_map()


func generate_map() -> void:
	if randomize_seed:
		gen_seed = randi()
	seed(gen_seed)
	
	if tilemap_layer != null:
		tilemap_layer.clear()
	draw_tile_square(max_room_dimensions, min_room_dimensions, total_rects)


func draw_tile_square(max_dimensions: Vector2i, min_dimensions: Vector2i, rect_amount: int) -> void:
	var coords_array: Array = []
	var next_coords_array: Array = []
	var all_coords_array: Array = []
	var random_offset_x: int = 0
	var random_offset_y: int = 0
	var completely_new = true

	for a in range(rect_amount): 
		var dimensions: Vector2i = Vector2i(randi_range(max_dimensions.x, min_dimensions.x), randi_range(max_dimensions.y, min_dimensions.y))
		random_offset_x = randi_range(0, map_dimensions.x)
		random_offset_y = randi_range(0, map_dimensions.y)
		for x in range(dimensions.x):
			for y in range(dimensions.y):
				next_coords_array.append(Vector2i(Vector2(x + random_offset_x,y + random_offset_y)))
				if all_coords_array.find(next_coords_array[y]) != -1:
					next_coords_array = []
					completely_new = false

		all_coords_array.append(next_coords_array)

		if completely_new == true:
			coords_array = next_coords_array
			tilemap_layer.set_cells_terrain_connect(coords_array, 0, 0, false)

Ideally, i’d like rectangles to generate with controlled minimal distances between them

  • generate a bunch of random rectangles
  • iterate over all rectangle pairs. If a pair overlaps - separate them on the shorter overlap axis, displace both rectangles equally, each by the half of total overlap
  • repeat the previous step until there’s no overlapping rectangles

Thanks