GridContainer not arranging Children appropriately for clicking

Godot Version

Godot v4.2.1.stable - Windows 10.0.22621 - GLES3 (Compatibility) - NVIDIA GeForce GTX 1660 Ti (NVIDIA; 31.0.15.5222) - Intel(R) Core™ i7-9750H CPU @ 2.60GHz (12 Threads)

Question

Hi there! I am attempting to duplicate a match 3 type game with some RPG elements and I can’t seem to get the GridContainer to arrange it’s Children so that they are clickable…

I have a Tile.tscn with a parent Control node and a Sprite2D child
The custom_minimum_size is set to 64x64 and the tile sprites are also that size.

I then have my Puzzle.tscn with a parent Node2D and a child GridContainer.
I programmatically instantiate a Tile.tscn and randomly load a sprite texture onto it and then add it to the GridContainer with: $GridContainer.add_child(tile)
The GridContainer is also set to a custom_minimum_size of 512x512 since my grid is an 8x8 with 64px size tiles.

It looks amazing when test playing the scene, see example here:

The problem is when I go to click on the Tiles or even when I click outside of the grid, it registers that I am clicking 10+ Tiles at once.
After some debugging I realized the Tiles’ global_positions were mostly all the same with some random ones being different.

Here is some of the console print to give an idea:
Tile: Tile_0_0at position: (0, 0)
Tile: Tile_0_1at position: (0, 0)
Tile: Tile_0_2at position: (0, 0)
Tile: Tile_0_3at position: (0, 0)
Tile: Tile_0_4at position: (0, 0)
Tile: Tile_0_5at position: (0, 0)
Tile: Tile_0_6at position: (0, 0)
Tile: Tile_0_7at position: (0, 0)
Tile: Tile_1_0at position: (0, 0)
Tile: Tile_5_0at position: (320, 64)
Tile: Tile_5_1at position: (320, 128)
Tile: Tile_5_2at position: (320, 192)
Tile: Tile_5_3at position: (320, 256)
Tile: Tile_5_4at position: (320, 320)
Tile: Tile_5_5at position: (320, 384)
Tile: Tile_5_7at position: (0, 0)
Tile: Tile_6_0at position: (384, 64)

Am I missing something obvious here to make sure the GridContainer lays out the 64x64 Tiles to not only look good visually (see above picture) but are also clickable?

Without any code, it’s hard to say.

What would be helpful would be how you fill it programatically and the print statements, at the minimum.

1 Like

Yeah you’re right.

Here is the function where I generate the board within the _ready() function:

func generate_board():
	grid.clear()
	for x in range(GRID_SIZE.x):
		var row = []
		for y in range(GRID_SIZE.y):
			var tile = create_random_tile(x,y)
			tile.name = "Tile_%d_%d" % [x,y]
			$GridContainer.add_child(tile)

And here is where the random Tiles are created. Essentially just different Textures thrown into the Sprite2D that is the child of the Control node:

var Tile = preload("res://Worlds/PuzzleMain/Tile.tscn")

func create_random_tile(_x,_y):
	var tile = Tile.instantiate()
	tile.tile_type = TILE_TYPES[randi() % TILE_TYPES.size()]
	tile.connect("tile_selected", Callable(self, "_on_tile_selected"))
	tile.custom_minimum_size = Vector2(TILE_SIZE, TILE_SIZE)
	return tile

And here is my debugging code I used to make the print outs above, and I have this connected to a DEBUG button in the scene to click after everything is loaded in:

func debug_print_grid_positions():
	for child in $GridContainer.get_children():
		print("Tile: ", child.name, "at position: ", child.global_position)

And in the Tile object I have this _input function to tell me when it is clicked:

func _input(event):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
		print("Tile Clicked: ", self.name, "at position: ", self.global_position)

Currently when I click, just once, anywhere in the scene, not even on a Tile, it says I am clicking a ton of Tiles, sample Print:

Tile Clicked: Tile_7_7at position: (483, 483)
Tile Clicked: Tile_7_6at position: (414, 483)
Tile Clicked: Tile_7_5at position: (345, 483)
Tile Clicked: Tile_7_4at position: (276, 483)
Tile Clicked: Tile_7_3at position: (207, 483)
Tile Clicked: Tile_7_2at position: (138, 483)
Tile Clicked: Tile_7_1at position: (69, 483)
Tile Clicked: Tile_7_0at position: (0, 483)

That line.

Each tile is connected to that method.

I don’t know how you set up that Tile scene, but I suspect it does exactly what it’s being told to do: propagate the click to each cell of the grid.

But that’s just guess work. From the above, that’s all I personally can say. I could be wrong, though.

1 Like

Also, personally, I would print() when it’s selected, not on a generic input, which might have been propagated through several controls depending on the settings.

I’d dump it in

func _on_title_selected():
    print("Tile Clicked: ", self.name, "at position: ", self.global_position)
    [ rest of code ]

but, it might be invalid, or complicate things…

1 Like

That makes complete sense. I need to figure out a way around the signal since it’s being connected to too many Tiles. Probably just keep the click detection in the main Puzzle.gd and not have it within the Tile.gd emitting a signal. Genious. I havent tested it yet, but when I do i’ll mark this as the solution! Thanks!