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

Area2D erroneously emits body_entered signal if collision mask *and* layer are reset. #45131

Open
Tracked by #45334
Whateverest opened this issue Jan 12, 2021 · 5 comments

Comments

@Whateverest
Copy link

Whateverest commented Jan 12, 2021

Godot version: v3.2.3

OS/device including version: Linux 5.10.2-2-MANJARO

Issue description:
I have an obstacle (Area2D) that "destroys" the player character(KinematicBody2D) on contact using the body_entered signal. I then hide the player, disable the collisions and start a timer.
I disable collisions by using:

set_collision_layer_bit(0,false)
set_collision_mask_bit(0,false)

After the timer has run out the player respawns at the start location. I do this by resetting the position and re-enabling collisions.
When the player respawns the Area fires the body_entered signal again even though the player character does not collide with the area anymore .

godotBug

This problem only appears if I reset both the collision layer and the mask.
If I reset only one of those it somehow works.

Did I stumble upon a Bug or is this documented behavior?

Other users seem to have a similar problem: https://godotengine.org/qa/56193/how-to-manually-set-the-position-of-a-kinematicbody2d

Steps to reproduce:

  1. Have a body enter an area (body_entered signal is emitted)
  2. Disable collisions and start a timer
  3. On timeout: Set the position of the body to somewhere outside the area and re-enable collisions
  4. body_entered is emitted again

Minimal reproduction project:
collission_example.zip

@Calinou
Copy link
Member

Calinou commented Jan 12, 2021

Related to #14578, #19271 and #25769.

@akien-mga akien-mga changed the title Area2D erroneously emmits body_entered signal if collision mask *and* layer are reset. Area2D erroneously emits body_entered signal if collision mask *and* layer are reset. Jan 12, 2021
@Whateverest
Copy link
Author

Thanks for the issues, #14578 (comment) contains a workaround for the problem.
Calling yield(self.get_tree(), "physics_frame") two times before re-enabling collisions seems to fix the issue.

@AttackButton
Copy link
Contributor

AttackButton commented Jan 15, 2021

Sorry. I've tested it more and this still is a bug related with #14578.

@Calinou Calinou added documentation and removed bug labels Jan 15, 2021
@AttackButton
Copy link
Contributor

AttackButton commented Jan 16, 2021

Thanks for the issues, #14578 (comment) contains a workaround for the problem.
Calling yield(self.get_tree(), "physics_frame") two times before re-enabling collisions seems to fix the issue.

The other workaround that I did find is to reconnect with the body_entered using the CONNECT_DEFERRED | CONNECT_ONESHOT every time the area is entered.

func _ready():
	$"../Area2D".connect("body_entered", self, "_on_Area2D_body_entered", [], CONNECT_DEFERRED | CONNECT_ONESHOT)
	start_pos = position


func _physics_process(delta):
	if dead:
		return
	move_and_slide(gravity)


func respawn():
	$"../Area2D".connect("body_entered", self, "_on_Area2D_body_entered", [], CONNECT_DEFERRED | CONNECT_ONESHOT)
	dead = false
	set_collision_layer_bit(0,true)
	set_collision_mask_bit(0,true)
	show()


func _on_Area2D_body_entered(body):
	if(body == self):
		dead = true
		set_collision_layer_bit(0,false)
		set_collision_mask_bit(0,false)
		hide()
		self.position = start_pos
		emit_signal("died",self)

@akien-mga
Copy link
Member

See #69407 for a 4.0 MRP, where the issue is still reproducible.

RunninglVlan added a commit to RunninglVlan/FirstGodotGame that referenced this issue Jun 4, 2024
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

4 participants