Spawning objects in 2d space with a certain distance between each other

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By matiss

Hi guys,
I created a script that spawn 10 objects at the start of the game in random location.

extends Node2D

var n = 10
var object = load("res://Object.tscn")

func _ready():
	randomize()
	spawn()
	
func spawn():
	for i in n:
		var x = rand_range(0,300)
		var y = rand_range(0,300)
		var rand_pos = Vector2(x,y)
		
		var object_instance = object.instance()
		object_instance.position = rand_pos
		add_child(object_instance)
		

How can I make sure that all of the objects are a certain distance from each other?
I want to leave a minimum distance between them.
Any help will be appreciated, thanks

:bust_in_silhouette: Reply From: Lopy

You could use a range [1, 10[, multiply by 30, and add a random [-5, 5]. This leaves you with a minimum distance of 20, without the placement grid being too apparent.
Also store the position of previously placed items to not select the same spot twice.

Edit

The idea described above was to place the elements in a grid. By checking that no two elements are in the same slot, you ensure a minimum distance between them. The problem then is that the grid will be very visible, which is why we shift the values a little.

Example code:

var placed_on_grid := {} # grid position -> null

while placed_on_grid.size() < 10:
    # Pick a position on the imaginary grid
    var x: float= int(rand_range(1, 10))
    var y: float= int(rand_range(1, 10))
    
    var grid_position := Vector2(x, y)
    if !placed_on_grid.has(grid_position):
        # Available slot
        # Take the slot
        placed_on_grid[grid_position] = null
        
        # Adapt to the size we wanted initialy
        var regular_position := grid_position*30
        
        # Shift the values to hide the grid
        regular_position.x += rand_range(-5, 5)
        regular_position.y += rand_range(-5, 5)
        
        print(regular_position) # Replace with what you want to use it for

Another option is to check the distance with every other picked position whenever we pick one. However the time is in O(n²), which might cause issues with big numbers of positions:

var wanted_positions := 10
var picked_positions := []
var minimal_distance := 20

while picked_positions.size() < wanted_positions:
    var x = rand_range(0,300)
    var y = rand_range(0,300)
    var rand_pos = Vector2(x,y)
    
    # Check if we can take this position
    var available := true
    var i := 0
    while i < picked_positions.size() && available:
        if rand_pos.distance_to(picked_positions[i]) < minimal_distance:
            available = false
        i += 1
    
    
    if available:
        # Take it
        # Remember we used this position
        picked_positions.append(rand_pos)
        
        print(rand_pos) # Replace with what you want to use it for

Sorry could you be a little more specific? I can’t quite understand what you mean.

matiss | 2020-12-28 20:06

can you be more specific please

druce | 2021-03-31 10:07

:bust_in_silhouette: Reply From: abcd1231406

You can use an Array object to save the data of distance~