godotengine / godotengine/godot
Mouse enter & exit signals trigger falsely when viewport is scaled (canvas_items mode) and mouse input is manually triggered
- Dominant language
- C++
- Stars
- 117k
- Forks
- 26.8k
- PR merge metrics
- PR metrics pending
Description
### Tested versions
- Reproducible in Godot 4.3 Mono.
### System information
Windows 11 - Godot Engine v4.3.stable.mono.official
### Issue description
This seems to have been fixed, but it may only have been for 2D? For a 3D project I had to use the manual position update when I move the camera to get mouse enter and exit to trigger: https://github.com/godotengine/godot/issues/69708
doing this I seem to get the same additional bug with 2D or 3D resulting from a few steps.
So, when calling something like this to manually update the mouse position:
```gdscript
var mouse_event = InputEventMouseMotion.new()
mouse_event.position = get_viewport().get_mouse_position()
Input.parse_input_event(mouse_event)
```
### Mouse Enter & Mouse Exit Signals will fire on an object at a different location to the mouse position if the viewport has been scaled and the stretch mode is set to canvas_items.
i.e. `get_viewport().get_mouse_position()` seems to be accurately produced, and you can draw things to the screen or make things follow to that mouse location and it works and produces the correct location and output, but somewhere in the processing of handling the simulated mouse input above, it will seemingly use a different or incorrect position value (maybe due to scale).
This causes other objects with mouse enter and exit signals to trigger when the mouse is not over them, or flickering to occur on the object you are mousing over.
I'm not sure if I'm doing something wrong, please let me know. Or in any case if there is a good workaround, please let me know.
### Steps to reproduce
1. Create a 2D scene
2. set Project Settings -> Display -> Window -> Stretch -> Mode to **canvas_items**
3. create a 2D node and give it these functions
```gdscript
extends Node2D
var mousePos = Vector2.ZERO;
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
var mouse_event = InputEventMouseMotion.new()
mouse_event.position = get_viewport().get_mouse_position()
Input.parse_input_event(mouse_event)
mousePos = mouse_event.position
print(mousePos)
queue_redraw()
pass
func _draw():
draw_circle(mousePos,20.0,Color.ANTIQUE_WHITE)
pass
```
4. Create a staticbody2D, with a sprite and a collision shape
5. give the static body a script with these functions
```gdscript
extends StaticBody2D
@onready var sprite = $Sprite2D
func _on_mouse_entered() -> void:
print("hit")
sprite.modulate = Color.BROWN
pass # Replace with function body.
func _on_mouse_exited() -> void:
sprite.modulate = Color.WHITE
pass # Replace with function body.
```
6. Run the game
7. Observe the proper behavior (do not scale the viewport yet)
8. Scale the viewport any way you'd like
9. Observe flickering and false positives.
https://github.com/user-attachments/assets/14fccba0-d70b-475d-9e46-5899931a7f77
### Minimal reproduction project (MRP)
[ScalingMouseEnter_MRP.zip](https://github.com/user-attachments/files/16948759/ScalingMouseEnter_MRP.zip)
Contributor guide
Research direction
Reproduce the issue with the linked ScalingMouseEnter_MRP.zip using canvas_items scaling and the Input.parse_input_event mouse-motion sequence. Trace the viewport mouse-position and mouse enter/exit processing from that entry point, then verify that scaled viewports no longer produce false signals or flickering in the provided reproduction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100