godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.93k stars 21.15k forks source link

Area2D registers collision of CharacterBody2D with disabled collision shape on scene load #88592

Open Emynator opened 8 months ago

Emynator commented 8 months ago

Tested versions

Reproduceable in:

System information

Godot v4.2.1.stable.mono - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1080 (NVIDIA; 31.0.15.5123) - AMD Ryzen 9 5900X 12-Core Processor (24 Threads)

Issue description

A scene is setup with 4 Area2Ds with a size of 512x512 placed around the origin. In the main scene this scene is instantiated and a CharacterBody2D with it's CollisionShape2D initially disabled is also instantiated. The CharacterBody2D is set to position (256, 256) and then it's CollisionShape2D is enabled with a SetDeferred() call.

Expected behaviour: only one Area2D's OnBodyEntered() function is triggered. Actual behaviour: all 4 Area2D's OnBodyEntered() function is triggered, then the other 3 Area2D's OnBodyExited() function is triggered.

Steps to reproduce

Using the MRP:

Minimal reproduction project (MRP)

CollisionBug.zip

alternative the repo is also available on github

dalexeev commented 8 months ago

See also:

Emynator commented 8 months ago

For anyone stumbling upon this issue in the future: A workaround I found is adding a flag and timer to the Area2D. as long as the flag is false the collision handling functions don't do any processing. On timeout of the timer the flag is set to true. A second timer on the CharacterBody2D which ideally is longer then the first one enables the CollisionShape2D. This way only the correct Area2D's OnBodyEntered function is triggered.

Despite a workaround existing I would still consider the current behaviour a bug.

AlexOtsuka commented 8 months ago

I have encountered this before, and here are a few things I know or believe about it:

keysole commented 8 months ago

It's bugged in 4.2.2 rc1 as well. Setting global position before adding didn't help, but waiting for 2 process frames did. Also, I don't think the default position is (0, 0), it's the position the node had before it was removed, at least it's 100% this way in my case. I also checked what the area thinks the body's position is in _body_entered signal and it actually prints the correct position, but the signal still fires.

AlexOtsuka commented 8 months ago

It's bugged in 4.2.2 rc1 as well. Setting global position before adding didn't help, but waiting for 2 process frames did. Also, I don't think the default position is (0, 0), it's the position the node had before it was removed, at least it's 100% this way in my case. I also checked what the area thinks the body's position is in _body_entered signal and it actually prints the correct position, but the signal still fires.

Yes you're right about the position, it was only (0, 0) specifically in this case because it was instantiating a fresh Node. It is indeed taking the Node's previous position into account.