Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing Area2D shape causes resend of body_exited and body_entered for enclosed body #19271

Closed
Tracked by #45334
Ramshell opened this issue May 30, 2018 · 12 comments
Closed
Tracked by #45334

Comments

@Ramshell
Copy link

Godot version:
3.0.2-stable

OS/device including version:
Ubuntu 18.04 bionic

Issue description:

If a body x is inside an Area2D (I mean the Area2D already received the body_entered(x)) and you resize the Area2D shape in such a way that the body is still inside the shape, it triggers body_exited(x) and then body_entered(x), like if the Area2D or the shape were being deleted and created again.
¿Is this the expected behavior?
I think that the body_entered and body_exited should be called only once in this case (i.e the body have never exited the area)

Steps to reproduce:
I have something like this:

  • Area2D
    • CollisionShape2D with a Rectangle

selection

This Area2D has an script that updates the rectangle with the mouse dragging (like a rectangle selection)

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
					$rect.shape.extents.x = 0
					$rect.shape.extents.y = 0
				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 a_rect = Rect2($rect.position.x - $rect.shape.extents.x, $rect.position.y - $rect.shape.extents.y, $rect.shape.extents.x * 2, $rect.shape.extents.y * 2)
		draw_rect(a_rect, color)

func _process(delta):
	print($rect.position, " ", $rect.shape.extents)
	pass

In the other hand I have a KinematicBody2D with a rectangle shape:

unit

The unit code is this:

extends KinematicBody2D

export var selected = false

func set_selected(value):
	selected = value
        print(value)

To test it you can put this nodes in a parent Node. You will have to draw a rectangle that overlaps the KinematicBody2D and see how it prints false -> true -> false -> true infinitely while the rectangle is being resized.

@swarnimarun
Copy link
Contributor

It's likely because it recalculates the whole thing again. Once size is changed, not really sure if it can even be fixed.

@Ramshell
Copy link
Author

Recalculate doesn't mean to resend the signals to the objects that have already been notified. I could try to fix it but I would like to discuss it first.

@eon-s
Copy link
Contributor

eon-s commented May 30, 2018

Is what usually happens, not what is expected.
There is another related issue with the inverse problem where you need to move the area for the Physics server to register the new shape size too #8325.

@swarnimarun
Copy link
Contributor

It seems old, is there some problems with fixing it. Why has it not been fixed yet.?
Cause it seems like sort of major issue, even though it has workaround it is common enough that many if fall prey to it. Is it breaking something to fix it.

@Ramshell
Copy link
Author

Ramshell commented Jun 2, 2018

I looked in the code and I couldn't find any clue on where could this bug be. Probably it is the part that calls update() in the CollisionShape2D::shape_changed() method.

@akien-mga akien-mga changed the title Dynamic Area2D strange behavior Changing Area2D shape causes resend of body_exited and body_entered for enclosed body Nov 8, 2018
@akien-mga
Copy link
Member

Confirmed in the current master branch (c4234b1), made this reproduction project: area2d_shape_resize.zip

@KoBeWi
Copy link
Member

KoBeWi commented Sep 20, 2019

I have a similar problem. I use KinematicBody2D with 2 shapes, one of which is disabled. When I disable one and enable another, any area the body is in gets body_enter triggered. This does happen even if both shapes are never disabled at the same time.

EDIT:
I actually fixed it with this

collider.set_deferred("disabled", false)
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
other_collider.disabled = true

@akien-mga
Copy link
Member

For the record, I checked if #33615 fixes this but it doesn't.

@fossegutten
Copy link
Contributor

fossegutten commented Jan 18, 2020

Disabling a CollisionShape2D also triggers the exited signal, which it probably should not. Caused some weird bugs in my game, luckily i had a comment in my code that saved me lots of debugging time!
Workaround: use collision_layer = 0 instead.

@KoBeWi
Copy link
Member

KoBeWi commented Dec 19, 2020

Still valid in 3.2.4 beta4

@AttackButton
Copy link
Contributor

AttackButton commented Jan 16, 2021

As I mentioned here: #14578 (comment), one workaround is to reconnect the body_entered (or area_entered) signal with the CONNECT_DEFERRED | CONNECT_ONESHOT options every time the signal is used instead of let it always connected.

Something like:
$Area2D.connect("body_entered", self, "_on_Area2D_body_entered", [], CONNECT_DEFERRED | CONNECT_ONESHOT)

@Rindbee
Copy link
Contributor

Rindbee commented May 22, 2023

Confirmed in the current master branch (c4234b1), made this reproduction project: area2d_shape_resize.zip

Using this reproduction project, I was unable to reproduce it in v4.0.stable.official [92bee43].

@akien-mga akien-mga added this to the 4.0 milestone May 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants