Clicking on buttons also placing tiles on tilemap

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

I have a TileMap that I can place tiles on by pressing my left mouse button. However, I also have buttons in my scene. When I press those buttons, tiles are placed underneath the button. I have looked at a solution that worked for someone:

Solution: Use _unhandled_input(event) for placing tiles
This solution is not usable because I need to drag and place multiple tiles. Using this only places one tile per click.

So basically I need to avoid placing tiles when clicking buttons, while still being able to drag and place multiple tiles. If there is any way to do this, hacky or otherwise, please let me know!

What are you currently doing that lets you drag and place multiple tiles on left mouse button events, but does not work when you use unhandled_input(event) to detect the left mouse button events?

You can try to do something like this:

func _unhandled_input(event):
if event.is_action_pressed("left_mouse_button_event_name"): 
	## Start placing tiles wherever the mouse is.
	# And maybe set input as handled.

func _input_event(event):
if tiles_being_placed and \
		event.is_action_release("left_mouse_button_event_name"): 
	## Stop placing tiles.

There are plenty of ways to decide exactly how you want to choose to filter inputs. The only key thing here is that you listen for two events (they can be the same event). One for starting to place tiles and one to stop placing tiles.

Vadalken | 2023-07-06 12:42

Sorry about the poor formatting of the code in my comment. Don’t know how to fix it.

Vadalken | 2023-07-06 12:44

I was using the Input singleton in the _process, as:

func _process():
     if Input.is_action_pressed("left_mouse_button_event_name"):
         add_cell(mouse_cell)

Also, thank you! Your idea solved my problem. Since you posted it as a comment, I cant mark it as a solution so I’ll probably answer my own question down in the answers. It’s slightly different than your solution.

BadLoaf | 2023-07-06 13:39

Just to clarify slightly after seeing your solution:
The reason I suggest two different functions is because you don’t want to start placing tiles if you are clicking a GUI element, but you might want to stop placing tiles even if the user moves the mouse over a GUI element before releasing the mouse button.

If you use unhandled_input(event) to detect the release then adding = false will not happen if some GUI element (like a button) sets the event as handled. Not necessarily relevant in your case, but these are the little details that can matter when making a good user experience.

Vadalken | 2023-07-07 08:35

Thank you, I never even thought of that! I was wondering why you placed the release event in _input().
I tried my old code though, and it seems to work even though I release the mouse on top of buttons, or any other GUI element. I wonder why.
I will add your suggestion to my answer though, just because it’s good to stay on the safe side.

BadLoaf | 2023-07-07 12:04

:bust_in_silhouette: Reply From: Focalworks

To address the issue of clicking on buttons and placing tiles on a tilemap, you can follow these steps:

  1. Determine the event listeners: Set up event listeners for both the buttons and the tilemap to capture the click events.

  2. Identify the button click event: When a button is clicked, handle the event by executing the necessary logic to determine the tile to be placed on the tilemap.

  3. Determine the tilemap position: Based on the coordinates of the click event on the tilemap, calculate the position where the tile should be placed.

  4. Place the tile on the tilemap: Using the calculated position, update the tilemap data structure or grid to include the new tile. This can involve changing the value of a specific cell in the grid or updating the corresponding data structure.

  5. Visualize the changes: Update the graphical representation of the tilemap to reflect the changes made, showing the newly placed tile at the calculated position.

By implementing these steps, you can ensure that clicking on buttons triggers the appropriate logic to determine the position and place the tiles on the tilemap accordingly.

:bust_in_silhouette: Reply From: BadLoaf

I figured it out with help from Vadalken in the comments, here is the code I used in case anyone sees this in the future:

var adding := false

func _unhandled_input(event):
	if event.is_action_pressed("left_mouse_button_event_name"):
		adding = true
	if event.is_action_released("left_mouse_button_event_name"):
		adding = false

func _process(delta):
	var mouse_position = local_to_map(get_local_mouse_position())
	if adding:
		add_tile(mouse_position)

I’m sure this isn’t the cleanest code out there but it works. Feel free to comment on this with better ideas.

As suggested by Vadalken (thanks again), it is more prudent to place the adding = false in _input(event) instead. This is to prevent the adding = false code not running in case the release event is handled by another GUI element.

This is the code:

var adding := false

func _unhandled_input(event):
    if event.is_action_pressed("left_mouse_button_event_name"):
        adding = true

func _input(event):
    if event.is_action_released("left_mouse_button_event_name"):
        adding = false

func _process(delta):
    var mouse_position = local_to_map(get_local_mouse_position())
    if adding:
        add_tile(mouse_position)

BadLoaf | 2023-07-07 12:08