+1 vote

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?

in Engine by (2,626 points)

2 Answers

+1 vote
Best answer

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.

by (2,626 points)
+1 vote

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.

by (16 points)

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.

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.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.