Checking if an event is within a collisionshape2d area

Godot Version

4.2

Question

Hi! I need to make a click/touch event check if it is within the CollisionShape2D area/shape (and if true then instantiate a scene). I know this issue would be automatically solved if I used the input_event(v,e,s) signal. However, I need to use _unhandled_input(event).

Is there a simple way within Godot to achieve this, or would I need to create a separate function that ‘compares’ the event location against the collision area location? -I’ve been trying the latter case unsuccessfully, if this is the only way to achieve it where could I find better info for it, thank you!

Is your collision area a rectangle or has it a different shape like a polygon or a circle?

  • If it is a rectangle, then you could use the function Rect2i.has_point() in order to test, if the mouse cursor is in the rectangle of the collision area. Ths would mean, that you need to convert the mouse position from viewport coordinates to local coordinates.
  • If the area is not a rectangle, then you would need to implement the decision-routine by yourself.

I would be interested in the reason, why you can’t use input_event() instead of _unhandled_input() in your case. Perhaps there is potential of improvements in the engine.

1 Like

Thank you Sauermann! Indeed it is a rectangle, I will try out with Rect2i.has_point() to see if it solves it.
When you say to convert to local coordinates you mean with to_local() , right?

The reason why I am trying to use _unhandled_input() instead: Once the scene is instantiated within the collisionshape area, if click somewhere else within this area it will just relocate this scene to that new location, not instantiate a new one.
But, if I click on the new scene itself (which is within the collisionarea) I don’t want it to relocate it, but it happens to relocate anyway (even if slightly)… From what I think I understood, I would be able to make the the collisionshape ignore my input if I used _unhandled_input() in this case. Is this the better practice for this situation?

I put this together, which shows one way of how I would probably do what I understand from your description utilizing input_event(): https://github.com/godotengine/godot/files/14234302/NestedAreas.zip
It also contains an example for converting mouse coordinates to local coordinates.

1 Like

Sauermann, thank you for the Rect2i tip. I searched a bit because of that and found Rect2, so I tried it out and I was able to get exactly the result I was looking for. I marked your reply as the solution because I believe Rect2i would probably have worked as well.
Interestingly, I did not need to convert the coordinates to local with this solution. I will post below my code for anyone that might need something similar. Regarding what you prepared for NestedAreas, this fantastic, I’m reviewing it now, again, thanks a lot for this you’ve helped me out big time! People like you are what make the Godot community so awesome!

var rect = Rect2()

func _ready():
	var collision_area = get_node("CollisionShape2D")
	var rect_shape = collision_area.shape as RectangleShape2D
	var rect_position = collision_area.position - rect_shape.extents
	var rect_size = rect_shape.extents * 2
	rect = Rect2(rect_position, rect_size)


func _unhandled_input(event): 
	if event is InputEventScreenTouch && event.pressed:
		sphere_location = event.position
		if is_event_inside(sphere_location):
			instantiate_sphere()

func is_event_inside(point: Vector2) -> bool:
	return rect.has_point(point)

Your NestedAreas solution is indeed much better than what I was trying to do. I will be implementing this method as well! :pray: