Is it possible to prevent mouse collisions on multiple overlapping Area2D signals?

Godot Version

4.1.1

Question

Hello! I have a collision problem. I have a packed scene with an Area2D and a square collisionshape2d.

I can drag these around the game window but if they are on top I don’t want the bottom zindex layer to detect the mouse event. Is there a option I am missing that prevents the area2d from going to the Area2D behind it?

Godot_v4.1.1-stable_mono_win64_8HCq7vTYe3

Are those windows using the actual Window class? Asking because that affects the solution as each Window is a Viewport.

It isn’t a window. It is just Node2Ds and TextureRects

image

I’ve fixed a similar issue in one of my projects but it was so convoluted.

It was done to prevent selection of 2 areas when overlapping.
Here it is fully working:
Godot_v4.2.1-stable_win64_uhxtc4NOAB

Here it goes.
Enjoy a good reading!

extends Node
class_name InteractionHandler

@onready var _selected_objects_list :Array[InteractableZone] = []

# This is a reference to the last object in the array.
@onready var _last_selected_object_in_list :InteractableZone :
	get:
		if ( _selected_objects_list == null or  _selected_objects_list.is_empty() ):
			push_error("Selected object list is null or empty.")
			return

		# Dunno why I've done it this way but there it is... If it works it works you know...
		var _last_object :InteractableZone = _selected_objects_list[ _selected_objects_list.size()-1 ]
		return _last_object


# I connect signals to funcions; nothing weird here.
func _ready() -> void:
	PlayerEvent.interactable_zone_selected.connect( _on_selected_object )
	PlayerEvent.interactable_zone_deselected.connect( _on_deselected_object )
	pass

# Basically when an Area2D (InteractableZone) is entered/exited by mouse
# it emits a signal, passing "self" as an argument, which then is received here.
func _on_selected_object( new_selected_zone :InteractableZone ) -> void:
	# It takes the zone as an argument and 'true' marks it as selected
        # making the marker and the speech bubble appear.
	_set_zone_as_selected( new_selected_zone, true )
	
	## Adds the zone to the "selection list"
	_append_object_to_array( _selected_objects_list, new_selected_zone )
	
	## This fixes an issue where more than one InteractableZone could be selected at the same time.
	for zone :InteractableZone in _selected_objects_list:
		if not (zone == new_selected_zone):
			_set_zone_as_selected( zone, false )
	pass

# Same concept as above but the other way around.
func _on_deselected_object( deselected_zone :InteractableZone ) -> void:
	_set_zone_as_selected( deselected_zone, false )
	
	_erase_object_from_array( _selected_objects_list, deselected_zone )
	
	if _selected_objects_list.is_empty():
		return
	
	# This fixes issues where the overlapping InteractableZone would not be selected automatically when exiting.
	# Maybe because Interaction or Mouse Movement outside the area.
	if _last_selected_object_in_list.can_interact():
		_set_zone_as_selected( _last_selected_object_in_list, true )

Use it as you will.

1 Like

I’ve just done something similar instead I look at zIndex. Your code is smaller though so I will accept the answer

1 Like

what do you mean look at zindex?
mind to share a snippet?

edit.:
I am glad I could help :slight_smile:

CurrentGridsOver is an array that is populated when the mouse hover is detected. GetZIndex() is just a method on the top node that just returns the .z_index. AllowMouseHover is the bool that prevents logic being ran on the child nodes.

func CurrentOverGrid():
	var highestZIndex = 0;
	var grid;
	if CurrentGridsOver.size() > 0:
		for contain in CurrentGridsOver:
			if contain.ContainerNode.GetZIndex() >= highestZIndex:
				highestZIndex = contain.ContainerNode.GetZIndex();
				grid = contain
		grid.ContainerNode.AllowMouseHover = true
		DebugUI.UpdateCurrentGridOverByZIndex(grid.ContainerGUID + ": " + str(grid.GridIndex))
		for contain in CurrentGridsOver:
			if contain.ContainerGUID == grid.ContainerGUID && contain.GridIndex == grid.GridIndex:
				var r = 1
			else:
				contain.ContainerNode.AllowMouseHover = false;
	
	if grid == null:
		DebugUI.UpdateCurrentGridOverByZIndex("NONE")
	
	return grid;
1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.