On_mouse_exit is triggering even when cursor remains on Area2D

Godot Version

v4.2.1.stable.official [b09f793f5]

Question

Hey all,

I am trying my hand at (my very limited understanding of) composition.

I have a top-level scene, that, in which, I want to put different objects. Object such as a table, a closet, etc.

I’ve made an object scene, where I’ve tried to make it as generic as possible. The object scene consists of an Area2D with a Sprite2D child (the sprite is set on the top level), a CollisionPolygon2D (the shape is determined on the top level), and (less important) an instantiated child Dialogue scene.

It works fine, to a degree. I can add the different objects with the same object scene in the top-levl scene, with sprites and the collision shapes working. I can click the objects and the dialogue gets correctly shown (Each object will have a different dialogue).

However, I want to show a cursor hand when I am hovering each object, and in inverse, I want the normal mouse cursor to show when I exit.

So I’ve added the_on_mouse_entered and _on_mouse_exited signals to the Area2D script and to determine whether to show a cursor hand or a normal cursor, I have an if condition in my _process method that checks a boolean set in those signals.

Weirdly enough, it works on my first instantiated object, but the second it does not work.

When I print the booleans, in the _process method, it indicates that the hover boolean (determined by the on_mouse_* signals) is continuously switching between true and false when I am hovering, but remains a steady false when not hovering the object.

To me, it seems to indicate that the _on_mouse_exited is also triggered even though the mouse remains on the object, but I am not sure. I am fairly new to Godot.

I hope this makes sense, and thanks for taking the time.

Can you share your code (especially for _process, _on_mouse_entered and _on_mouse_exited)?

Yes, of course.

I will also share a screenshot, so it also gives some context of the tree.

extends StaticBody2D

@export var dialogue_key = ""
@export var sprite_path = ""

var area_active: bool = false
var mouse_entered_object: bool = false

func _ready():
	pass#Signalbus.connect('can_hover', enable_hover)
	
func _on_mouse_entered():
	mouse_entered_object = true

func _on_mouse_exited():
	mouse_entered_object = false

func _on_dialog_area_body_entered(_body):
	area_active = true

func _on_dialog_area_body_exited(_body):
	area_active = false

#func enable_hover(bool_key, area_name):
	#if area_name == dialogue_key:
		#area_active = bool_key
	
func _on_input_event(_viewport, event, _shape_idx):
	if area_active && event.is_action_pressed("left_click"):
		Signalbus.emit_signal("display_dialogue", dialogue_key)

func _process(_delta):
	if area_active && mouse_entered_object:
		Input.set_default_cursor_shape(Input.CURSOR_POINTING_HAND)
	if !area_active || !mouse_entered_object:
		Input.set_default_cursor_shape(Input.CURSOR_ARROW)

Screenshot:

Mhm, cannot reproduce your issue. Works fine for me.

As an alternative, you could replace your ObjectSprite with a TextureRect and change it’s default_cursor_shape to “Pointing Hand” to get all of this for free.

That is so strange. It might be something related to the whole setup, how it is introduced into the Office scene.

I tried the TextureRect, and it works perfectly. I will use that.

Thank you so much!

EDIT:

I will have to do some testing when I get home. I have two conditions that needs to be true, that the cursor is hovering and the player sprite is near the object. But it looks very promising.

2 Likes

Hey again,

Just a bit late, life took precedence.

I like the idea with texturerect, but the problem is actually not so much that the StaticBody2D node doesn’t work, but it stops working with multiple objects instantiated from the same scene. Let me explain in more detail.

I have a scene in which I want to instantiate the same object multiple times (I use it as a generic object, where I can pass a sprite for them to look differently).

In this object scene, I have an Area2D that has a script. I check whether the Player has entered the vincinity. If the player has, it toggles a boolean. If this boolean is true AND the mouse is hovering the StaticBody2D, I change the default cursor.

I also change the cursor in the _process method, so it can change as the Player enters the vincinity (instead of having to rehover).

It works for the first instantiated object, but for the second it stops working. If I remove the first instantiated object, the second works.

So I have some ideas, but it seems like I am misunderstanding a fundamental part of Godot.

Thanks for your patience!