Ways of randomly arranging the buildings in my scene

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Ertain
:warning: Old Version Published before Godot 3 was released.

I have a TileMap scene which is filled with grassy tiles. I’m trying to randomly place houses. Each of the houses are in different scenes, and they are added to the main scene as children (so I use a great deal of the instance() method).

How can I place these houses such that they aren’t overlapping one another? I have thought of randomly choosing a place with a Vector2 declaration (i.e. var ranom_place = Vector2(randi() % width_of_scene, randi() % height_of_scene)), then checking that area for any previous houses by utilizing the map_to_world() method. However, that seems too resource intensive. I have also thought of just checking the corners of where the scene will be (in relation to the root scene), but that sounds too complex.

So how could I do this?

:bust_in_silhouette: Reply From: Chris

What about splitting the scene up into squares based on the largest size of the ‘house’ you plan on placing?

let’s say it’s 1024x1024 px grid. largest house size is 32px, so that means you will have split your grid up into 32 rows, 32 columns.

Now pick 2 random numbers 0-32 called A and B. Then place this ‘house’ at x=A*32 and y=B*32, rinse repeat

As long as you ensure that the random 2 numbers have not been picked yet. they wont overlap. Simply keep an array of your chosen random numbers, make a function that loops through and ensures that the passed A/B, X/Y does not already exist.

Depending on the size of your ‘house’ sprites you can then add some more randomness… Say the largest house is 32x32… make your grid that you split up into be 64x64… that means you have 16x16 columns, now when you do your x=randomA*64 and y=randomB*64 you can add another random number between 0-32 to the x and y so that you now position the 32x32 within the 64x64 Heck even add in rotation if that is something you see as being feasible.

That’s a good idea, Chris, though I need to get the height and width of the add-on scenes in pixels. I’ve tried doing something like get_node("House1").get_used_rect().size, however this returns values that are translated into grid values (in other words, it tells me that the add-on scene is 4 tiles by 6 tiles). So I need to somehow convert that into pixel values.

Ertain | 2017-09-23 18:38

I have also thought of using Area2D nodes to the detection. However, I can’t figure out how to exactly detect when they’re colliding.

Ertain | 2017-10-01 06:27

:bust_in_silhouette: Reply From: Ertain

Okay, it’s taken me weeks. But I think I’ve solved this one.

To check whether my houses are colliding, what I do is check them via a Rect2 object. I do it like this:

# Height and width of House1
var h1 = get_node("House1").get_used_rect().size
# Height and width of House2
var h2 = get_node("House2").get_used_rect().size

# Place on the map for House1
var w = Vector2(randi() % int(world_width - h1[0]),
               randi() % int(world_height - h1[1]) )
# Place on the map for House2
var v = Vector2(randi() % int(world_width - h2[0]),
               randi() % int(world_height - h2[1]) )

# Check to see whether they're overlapping each other using a Rect2() object.
if ( Rect2( v, v + h2 ).has_point(w) ):
          print("They're intersecting.")

I found the answer in this question.