0

Hey I'm looking for some help.

I am trying to populate a screen with panels/2D Nodes of different set sizes. I'll be using 2 arrays to be able to do this but the issue I am coming across is that I'm not sure how to do this without causing gaps between the panels/Nodes.

So what I'm hoping to do is something like this while avoiding empty spaces like this(see the white square in the middle). I just don't have the technical know how to make this happen. I can always do these things manually but I am hoping to be able to just do it randomly.

I suppose the best way to think about it is like Tetris but it fills it out on it's own

If you require more information, I will be happy to provide but I don't think any else if needed in this instance.

Thanks for any help in advance

user3618687
  • 113
  • 1
  • 11

1 Answers1

0

The result you want can be archived by partitioning the viewport area. You are going to need more constraints to get what you want (e.g. minimum width, minimum height). Which reminds me, I don't know how you want this to behave when the viewport is resized.

Anyway, the idea is to make a tree structure (and for that you can take advantage of the scene tree), where the root has the area of the viewport. It decides how to split it in two (either vertically or horizontally) using random, and then creates two children for those areas. The children do the same with the area they were given, until you get to a point where splitting would violate the constraints.

To decide where to divide, first figure out the valid range for an horizontal and vertical division. If the range is empty you can't do that division. If you can't do either horizontal or vertical division, then don't divide.

The range for a division goes from the minimum to the total minus the minimum. Something like this:

var range_min_x := minimum_width
var range_max_x := width - minimum_width
var can_divide_x := range_min_x < range_max_x

var range_min_y := minimum_height
var range_max_y := height - minimum_height
var can_divide_y := range_min_y < range_max_y

if can_divide_x and can_divide_y:
    if randf() < 0.5:
        divide_x(range_min_x, range_max_x)
    else:
        divide_y(range_min_y, range_max_y)
elif can_divide_x:
    divide_x(range_min_x, range_max_x)
elif can_divide_y:
    divide_y(range_min_y, range_max_y)
else:
    # don't divide
    pass

And then those functions look like this:

func divide_x(min:float, max:float):
    var division := int(rand_range(min, max))
    create_child(Rect2(0.0, 0.0, division, height))
    create_child(Rect2(division, 0.0, width - division, height))

func divide_y(min:float, max:float):
    var division := int(rand_range(min, max))
    create_child(Rect2(0.0, 0.0, width, division))
    create_child(Rect2(0.0, division, width, height - division)) ​

Using int is important to avoid one child rounding down and other rounding up, leaving a one pixel gap.

Then in the create_child function you would be creating and adding a child with the given dimension, which would then also be divided by the same means.

You are not going to have empty areas because you would always be adding pairs of children that make up the total of the parent area.

Theraot
  • 31,890
  • 5
  • 57
  • 86