Check if Area2D fully encloses PhysicsBody2D

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Michael Stevens

I am working on a top down 2D game and I want to create a node that responds to the player (a PhysicsBody2D node) moving into an Area2D. I know Area2D offers signals for body entered and exit events, but I want the event to only be triggered when the Player is fully enclosed by the Area2D.

I know the Rect2 class has an enclosed(Rect2) method, which might be helpful if I could only find a way to extract a Rect2 from a PhyiscsBody2D. All the ways I’ve tried require using specific instance details of the objects in question, which I don’t think is an acceptable solution. I should be able to detect if a PhysicsBody2D is enclosed by an Area2D regardless of CollisionShape2D and scale specifics. Any ideas?

Thanks!

:bust_in_silhouette: Reply From: kidscancode

By default, Area2D just checks for overlapping. If overlapping is detected, you could then compare the relative positions of the bodies, but that will require you to know their sizes. This information is in the extents property of the CollisionShape2D’s shape (don’t forget, extents is measured from the center, so it represents half the shape’s size).

You could also build two Rect objects containing the information and use Rect2.encloses().

Below, if body is a reference to the physics body, and area is a reference to the Area2D:

var body_extents = body.get_node('CollisionShape2D').shape.extents
var area_extents = area.get_node('CollisionShape2D').shape.extents
var body_rect = Rect2(body.global_position - body_extents, body_extents * 2)
var area_rect = Rect2(area.global_position - area_extents, area_extents * 2)
if area_rect.encloses(body_rect):
    print("body is fully inside area!")

Note you can cache these values if you need to check them often, and just update the Rect positions whenever you need to perform the check. This is just an explicit example of how to get the information.

Note that this will only work for RectangleShape2D, only if the PhysicsBody2D has only one CollisionShape2D child and only if the PhysicsBody2D has not been rotated or scaled. For a more general solution, I would put extra Area2Ds around the border of the main Area2D, if the body is overlapping with the middle Area2D and not any of the bordering Area2Ds then it’s completely inside the area.

uzimonkey | 2018-12-30 15:52

I have not tried it but probably Shape2D.collide_and_get_contacts can be used to test if overlaps but there are no contacts on the limits.

eons | 2018-12-30 17:19

True, but the original question did request Rect2 shapes. Also, note that a PhysicsBody2D should never be scaled.

kidscancode | 2018-12-30 20:48

@eons this is probably the best solution, certainly much easier to set up than my idea.

uzimonkey | 2018-12-31 04:44

I didn’t manage to make this work, Shape2D.collide_and_get_contacts still reports points of contacts even when there is none, I think it’s a bug.

votagus | 2021-02-11 02:33