Blocking mouse input

Godot Version

4.2.1

Question

I have a scene with the following structure:

image

Where the Node2d on the red arrow is implementing some drag-n-drop behaviour while the Control “above” it just contains a bunch of ColorRects, set to do:

image

I would expect (and desire) for the drag-n-drop to NOT work under those rectangles, but in fact wherever I click, the below object is getting dragged anyway.
Is there a way to make sure the bottom Node2d doesn’t receive any mouse input?

1 Like

If you are using _input() in the Node2D it will be always processed first. You’ll need to use _unhandled_input() More info here Using InputEvent — Godot Engine (stable) documentation in English

If you are using the Input singleton then it will always be processed. The InputEvent system and the Input singleton are different system that work independently. You’ll need to implement it using _unhandled_input()

2 Likes

Thanks, I’m definitely using input:

func _input(event):

	if event is InputEventMouseButton:
		var mouse_position = get_global_mouse_position()

		if Input.is_action_just_pressed("click"):
			is_clicked	   = true
			is_dragged	   = true
			drag_start_pos = position

etc.etc..

I tried to convert it to _unhandled_input() but it stopped working.
I though I had set the overlying masking ColorRects erroneously, so I completely removed the whole section about the Node2d, so I have only a background and the draggable Node2d in my scene now.
Even with that and _unhandled_input nothing moves anymore.
If I set it to _input() the Node2d moves, but the above Control doesn’t “mask” the inputs…

If it does not work is because some other Control node is consuming the events. Try clicking on it while the game is running and check the Misc tab in the Debugger dock. Check if Last Clicked Control field shows anything. If it does, set that control Control.mouse_filter to Ignore and repeat.

3 Likes

That’s a very cool trick, thanks for pointing at that!

Interestingly enough, the even gets consumed by the Background node, which A) is not a Control but a ColorRect and B) is under the Node2D one.

Is this expected?

1 Like

A ColorRect inherits from Control and has its mouse_filter property set to Stop by default, so, yes that’s expected.

It does not matter where in the tree the Control is. Their _gui_input() function will always execute before any _unhandled_input() function of any other node and because mouse_filter gets processed at the same time of _gui_input() the InputEvent will be set as handled and won’t continue being processed.

4 Likes

Thanks, that explains.

It seems that if I wanted for this to work, I’ll have to disable every other node’s mouse behaviour forever, which seems very unpractical to me!

Is there another way to approach this problem?
What I’m trying to get is basically a section of the screen (and only that one) to be draggable.
Such section (imagine it’s a board or a map or a sheet of paper) can be dropped-on some other pieces, so if you were to click on the pieces, you would drag them, otherwise clicking on an empty region of the board, would allow you to drag the board itself.
Clicking outside of that region would NOT result in the board to be dragged.

The last behaviour is what I was trying to implement now.

1 Like

If I understand you correctly, you have a board (Node2D-derived node) and some pieces (Node2D-derived node) and want to make the board dragable, when dragging starts within the area of the board, where no piece is located.

One way I believe it is possible to achieve this is:

A different approach would be to represent board and pieces as Control-derived nodes and use the Drag & Drop implementation of Godot (it depends on your requirements, if this approach is feasible).

Personally I consider mixing Control-nodes and Node2D-nodes in most cases not a good idea. Have you thought about replacing the ColorRects by Node2D-derived nodes like for example Polygon2D or Sprite2D?

1 Like

If I understand you correctly, you have a board (Node2D-derived node) and some pieces (Node2D-derived node) and want to make the board dragable, when dragging starts within the area of the board, where no piece is located

Yep, that part is working already.
“Pieces” on the “board” just get parented to the board itself. So if you click on one of them, it’ll take precedence, otherwise it’ll mean you clicked on the board, and you’re dragging it and all the pieces with it.

  • Haven’t thought through the act of stopping dragging, but it is likely that you will need to take care of a few edge cases.

That’s the missing piece of the puzzle. I’d like to define areas that act like a mask and prevent for the whole logic above to happen.
I thought it was as simple as “covering” those areas with an object that would stop the mouse event, but as it turns out, that won’t work…

1 Like

I believe, that we have misunderstood each other. Apologies, I try to be more precise:

  • With “the start of dragging” i meant handling the act of moving the mouse directly after pressing the mouse-button (initialization of a dragging operation)
  • With “the act of stopping dragging” I meant handling the release of the mouse-button during a drag-and-drop operation (ending of a dragging operation)

Based on your reply, I would describe your use-case:

  • You have a board (Node2D-derived node) and some pieces (Node2D-derived node) and want to make the board dragable, when dragging starts within the area of the board, where no piece is located. Additionally the board should not be draggable in certain other “no-board-drag” areas within the board.

Using the method of my previous post, adding additional CollisionObject2D that represent the “no-board-drag” areas should be straight forward by simply discarding events in their _input_event function that would cause “the start of dragging”, so that the event doesn’t reach the board.

3 Likes

Thanks, I’ll give your suggestion a go!

To make it 100% clear, imagine a situation like this: http://3.bp.blogspot.com/-LFn8SXDl-vE/VIeK6lVGcvI/AAAAAAAAQ1A/Ti_shD6-D5Y/s1600/1.jpg

Where the aforementioned board is the section on screen left side, the “masked zone” is the character sheet at the centre (it’s not exactly my case, but I hope you get the idea)

1 Like

I realized I haven’t answered this.
I think that might be the core of the issue actually… for a game that’s essentially “all UI” what would be the best way to structure the data?

My ideal mental mode is to be able to organize the whole thing like this:


so that mouse interactions (clicks, dragging, etc) would be driven by the camera visibility of the UI component under the pointer.

The reason I’m thinking this could be a good approach is that then, each object could implement their own behaviour on what to do when they’re clicked over

1 Like

If you have an “all UI” approach, then I would suggest to use Control-nodes and not Node2D-nodes.

Control-nodes are intended to be used for creating UI’s. They even provide a built-in drag & drop behavior.

Also if you have different separated parts of the UI, you might want to look into SubViewports and SubViewportContainers.

1 Like

I finally found time to go back to this and play a bit more…

I build an minimal debug scene from zero, looks like this:
image

where the board control contains a dark grey rect spanning the whole screen and the mask Control contains light grey rect covering half of the dark board:

The script attached to board is just implementing a minimal dragging behaviour relying on _gui_input().

The mask is set so that the Control itself is ignoring mouse events while the light grey rect is stopping them.
This seems to give me what I needed, I’m still curious to test your proposed Viewports approach to see if there’s anything better with that, meanwhile some questions:

  • do you foresee any issues with this method. It seems overly simplistic, but so far does what I need?
  • you mentioned Control’s built-in drag method, is this documented? I looked for it but could only find reference to methods like _get_drag_data() or _can_drop_data()

Thanks!

1 Like

That entirely depends on your requirements. If you do only stuff like dragging onto a different control in the same Viewport, then it should be doable.

Yes, these are the relevant functions. You could have a look at this demo project:

2 Likes

Yep yep, saw that before, but it implements drag and drop of data, more than “just dragging the board around and updating its transform”, right?

I feel that part needs to be done by hand still.

1 Like