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 duplicate signal when changing CollisionPolygon2D Polygon property #25769

Open
Tracked by #45334
ghsoares opened this issue Feb 10, 2019 · 6 comments
Open
Tracked by #45334

Comments

@ghsoares
Copy link

Godot version:
3.1 Beta 3

OS/device including version:
Windows 10 Pro

Issue description:
I'm trying to create dynamic 2d water, with damping and dispersion physics in the water surface. The water has Area2D with CollisionPolygon2D to detect RigidBody2D collision to calculate speed and apply force in a surface vertice. But the CollisionPolygon2D has the same poygon as the body (note: the water body and surface is drawed, not using a Polygon2D), so every frame is changing. But when a body enter the water, duplicate the "splash" function, but when the Collision is not changed, the "splash" function is called once.

OBS: I already tried using _physics_process(delta) function in instead of _process(delta) function to change the polygon, but the signal output more.

Steps to reproduce:

  1. Create a Area2D;
  2. Create a CollisionPolygon2D as child;
  3. In a script, every frame change the 'polygon' property of the CollisionPolygon2D;
  4. Connect the 'body_entered' signal to the script;
  5. To analyse the output, put a print function on the signal;
  6. Put a RigidBody2D (or other body falling to the Area2D) on the scene;
  7. Run the scene.

Minimal reproduction project:
collision duplication.zip

@spikestheraccon
Copy link

I have same issue when I use Animation Player and change polygons dynamically. At the end of animation I tried to disable collision, but signal still emit. It makes impossible do "slashes" with Area2d+CollisionPolygon2d

@KoBeWi
Copy link
Member

KoBeWi commented Nov 6, 2020

Still valid in 3.2.3

@Zylann
Copy link
Contributor

Zylann commented Jul 2, 2021

Similar to #19271?

@ghsoares
Copy link
Author

ghsoares commented Jul 2, 2021

@Zylann It seens that both issues is occurred by the same bug, so yes

@KoBeWi
Copy link
Member

KoBeWi commented Nov 16, 2024

Looking at the source, the polygon is clearing its physics shapes before rebuilding the polygon, which I assume is what's causing the collision to exit.
Unless there is a way to avoid that, we should just document it. You can workaround it by having multiple polygons and cycling between them.

@LaysDragon
Copy link

I come out this workaround to conquer the duplicate events during polygon switching dynamic,not sure the performance impact and also it would delayed the events.

test.mp4

Since every polygon switching always remove every tracked body and re-add body still in area,I tracking the body between every switching to find out which body are new and which body are gone.

Code
var _body_shapes_counter: Dictionary = {}
var _body_shapes: Dictionary = {}
var _backup_body_shapes: Dictionary = {}

enum TrackingState {
    RESETTING = -1,
    RECOVERING = 1,
}
var _track_state := TrackingState.RECOVERING

signal body_shape_entered_debounce(body_rid: RID, body: Node2D)
signal body_shape_exited_debounce(body_rid: RID, body: Node2D)


func _on_body_shape_entered(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:
    # remove the transfer event between polygons in area
    if _body_shapes_counter.has(body_rid):
        _body_shapes_counter[body_rid] += 1
    else:
        _body_shapes_counter[body_rid] = 1
        _on_body_shape_entered_reload_debounce(body_rid, body, body_shape_index, local_shape_index)

        
func _on_body_shape_exited(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:
    # remove the transfer event between polygons in area
    if _body_shapes_counter.has(body_rid):
        _body_shapes_counter[body_rid] -= 1
        if _body_shapes_counter[body_rid] == 0:
            _body_shapes_counter.erase(body_rid)
            _on_body_shape_exited_reload_debounce(body_rid, body, body_shape_index, local_shape_index)

func _on_body_shape_entered_reload_debounce(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:
    if _track_state == TrackingState.RESETTING:
        _track_state = TrackingState.RECOVERING
    _body_shapes[body_rid] = body


func _on_body_shape_exited_reload_debounce(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:
    if _track_state == TrackingState.RECOVERING:
        for rid in _body_shapes:
            if not _backup_body_shapes.has(rid):
                body_shape_entered_debounce.emit(rid, _body_shapes[rid])

        for rid in _backup_body_shapes:
            if not _body_shapes.has(rid):
                body_shape_exited_debounce.emit(rid, _backup_body_shapes[rid])
        _body_shapes.erase(body_rid)
        _backup_body_shapes = _body_shapes.duplicate()
        _track_state = TrackingState.RESETTING
    else:
        _body_shapes.erase(body_rid)

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

6 participants