+1 vote

Hello,

I am currently trying to add new features to Escoria Framework (https://github.com/godotengine/escoria), which is a Libre framework for the creation of point-and-click adventure games in Godot Engine.

The current classic design of a scene is this one :
Node2D (script: scene.gd)
|- TextureFrame (script background.gd)
|- linked game.scn node (script: game.gd)
|- TextureButton (script: item.gd)
|- TextureButton2 (script: item.gd)
|- linked player scene (script: player.gd)
|- Navigation (script: terrain.gd)
|- NavigationPolygon2D

My problem lies between the TextureFrame and the items' TextureButtons.

The background node (TextureFrame) catches all inputs from the user (mouse clicks) and calls specific methods from the game node (game.gd) that manages clicks, thus making the player move in the scene.
Concerning mouse pointer hovering an item, this event is managed directly by TextureButtons, which extend Control. The mask defining the "hover zone" is either the whole TextureButton (rectangle), or a mask image parameter.

I want to be able to define an Area2D node (extends CollisionObject2D, thus manages mouseenter/mouseexit events) with a CollisionPolygon2D child, allowing the user to define "hover zones" directly in the editor, instead of having to create and/or modify a mask image for this purpose.

The problem is that the background node (TextureFrame) avoids my Area2D node to catch mouse_enter event, since it catches all mouse events before.

You can have an illustration with the demo at this URL: https://github.com/StraToN/escoria-test .
1/ Load the res://scenes/rooms/desk/scene.scn and run it.
2/ Try to hover the shelf (Area2D) on the left : nothing happens.
3/ Try to hover the ice cream on the right (TextureButton) : the item name appears.
4/ In the editor, select the background node and check "Ignore Mouse". Re-run.
5/ Hover both items : it works, since mouse is disabled in background node, Area2D can catch it.
6/ Try to click anywhere on the terrain: the player doesn't move, which is normal since mouse is ignored.

Thanks for any hints :) !

in Engine by (225 points)
edited by

Bit of a large code base to casually peruse ;) but here is an idea;

in background.gd you could try using func _unhandled_input(event) rather than func _input(event) this should give your area2d a chance to grab it first according to the docs

edit:
actually seems area2d gets lower priority than even _unhandled_input , which would properly mean you'd have to manually test mouse position against your all of your hover aread2d's

@guppy42: Indeed according to this image (from this page InputEvent docs), you are right.

InputEvent flow

Of course, I don't want to have to perform an in-house "has pixel(pos2D)" on every Area2D/CollisionPolygon2D of my scene (even if this could be optimized by filtering this list), as this will quickly become impossible.

Technically, what I'm looking for is basically the opposite function of accept_event(), basically saying "ok, I received that event, but I won't manage it myself and let one of my children take care of it".

I also thought about changing the type of node for the background (say use a Sprite instead of a TextureFrame for example), but I'd have to impact massive changes in the background.gd script, that explicitely extends Control. I do believe TextureFrame is the right node type for this, though.

edit: I'm wondering : wouldn't it be better then to define a new Area2D node for the whole game area, that would take care of inputevents (thus background2D node attached) instead of the TextureFrame (which would then simply be a simple image displayer, no script attached)? That way, no Control node would interfere in the process. I'll try it tonight, but if someone already knows what will happen... ;)

Spendt at bit of time fiddling and I found out two thing

  1. bg_music is 40x40 in the upper left corner you should make it 0x0 or it will catch the mouse ;-)
  2. You have to stop using TextureFrame as it seems to blackhole all mouse input and there is no way to stop it.

It makes sense tho as Control items are meant to be used for UI elements which would always be "on top" to be usefull.

I see that you arrived at the same conclusion - 7 hours earlier, should've checked your comment for edits I guess ;^)

  1. Indeed. This one is part of the Escoria framework, I'll look further to know why is visible.

  2. Indeed, I actually found a solution that fits my needs.

  • First, TextureFrame becomes a simple image display, nothing more. The script that was attached to it (background.gd) isn't attached anymore.
  • Instead, create a new Area2D node as child of root.
  • Add a CollisionShape2D node as child of this Area2D. Set its pos at (width/2, height/2). Create a RectangleShape2D in the inspector, set its extent to (width/2, height/2).
  • Attach the background.gd script to the Area2D and edit it so it now extends Area2D instead of Control
  • It works ! :)

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.