How does the Area2d should behave?

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

I wanted to do a rectangle drag selection of (1) units (KinematicBody2d with a RectangleShape2D as a child)

In order to do this I’ve created an (2) Area2d with a CollisionShape2D child with a RectangleShape2D inside, then I attached a script to see if the body_entered and body_exited are being triggered whenever the rectangle overlaps a unit.

To test it I have a tree that looks like

  • Node2D
    • Area2D (2)
    • KinematicBody2d (1)

So when I drag the mouse with the button clicked I resize the RectangleShape2D.shape and change its position. Finally what happens is that body_entered and body_exited are triggered, but every time I resize the rectangle (each frame) both methods are triggered again (body_exited first, and then body_entered, as if the rectangle were being deleted and created again).

Here is the code that resizes:

extends Area2D

var dragging = false
var color = Color(0, 0, 1, 0.3)

func _ready():
	$".".connect("body_entered", self, "select_unit")
	$".".connect("body_exited", self, "deselect_unit")
	pass
	
func select_unit(body):
	body.set_selected(true)

func deselect_unit(body):
	body.set_selected(false)

func _input(event):
	var mouse_pos = get_global_mouse_position()
	if event is InputEventMouseButton:
		match event.button_index:
			BUTTON_LEFT:
				if event.is_pressed() and not event.is_echo():
					dragging = true
					$rect.position.x = mouse_pos.x
					$rect.position.y = mouse_pos.y
				elif not event.is_pressed():
					dragging = false
					print($rect.position.x, " ", $rect.position.y)
					$rect.shape.extents.x = 0
					$rect.shape.extents.y = 0
					update()
	elif event is InputEventMouseMotion:
		if dragging:
			$rect.shape.extents.x += event.relative.x / 2
			$rect.shape.extents.y += event.relative.y / 2
			$rect.position.x += event.relative.x / 2
			$rect.position.y += event.relative.y / 2
			update()

func _draw():
	if dragging:
        var x = $rect.position.x - $rect.shape.extents.x
        var y = $rect.position.y - $rect.shape.extents.y
        var width = $rect.shape.extents.x * 2
        var height = $rect.shape.extents.y * 2
		var a_rect = Rect2(x , y, width, height)
		draw_rect(a_rect, color)

So is this the expected behavior? I mean the fact that every time I resize the shape the body_entered and body_exited are triggered again. If no, how could I do what I’m trying to do?

:bust_in_silhouette: Reply From: eons

This is not the way we like to see on an area, I think it is a bug, but probably you won’t get a good response anyway, for selections better “cast a shape”.

use get_world2D().direct_space_state.intersect_shape and store the result with the list of bodies to work with it, you just need to construct the query object.