Search Unity

Limited use of Physics2D shape cast with CompoundCollider2D

Discussion in 'Physics' started by djeedai, Mar 22, 2019.

  1. djeedai

    djeedai

    Joined:
    Sep 28, 2018
    Posts:
    6
    This is not a bug so much as a very impractical and unclear limitation on the current API.

    Any shape cast method in Physics2D (e.g. BoxCastNonAlloc) used to query more than the first collision will report the list of colliders hit, with a single hit point/normal per collider. This is not very clear at first from the documentation, although retrospectively (after debugging for an hour and realizing that happens) the documentation indeed talks about "hit colliders" and not "hit points". In general this is fine, since the collider is convex, so there's no possibility for e.g. a box to collide with more than one edge of a convex.

    For some use cases however, like TilemapCollider2D, you want to be using a CompositeCollider2D to merge individual tile colliders into a single one for performance reasons, as recommended in particular by the official tutorials. This means that whatever the circumstances the shape cast will return a single hit, since there is a single global compound collider merging all tile's individual colliders, assuming here that the scene has a single Tilemap for simplicity. Yet it is fairly common that the union of all tiles form a concave shape (e.g. the entire game world is generally concave). In that case, only the closest point will be reported, and a single hit collider returned, the global compound one. This renders calls to BoxCastNonAlloc(hits[2+]) no better than a simple BoxCast() or BoxCastNonAlloc(hits[1]); that is, there is no hope trying to return other hit points past the closest one with a concave compound collider, this will never happen.

    While this is technically the correct result (there is a single compound collider replacing the many individual tile ones), conceptually in many use cases what's interesting is not so much the Collider2D object but the hit point and/or normal. In particular, any piece of custom logic (most notably: custom character controller) will be forced to either stop at the first hit and cast a second shape to get the next hit point/normal, or go back and inspect all collider paths to see which edges in the underlying convex shapes have effectively been hit by the cast (that is, perform some manual collision detection). Both alternatives are equally bad for performance, when the information about all hit points is most surely available from the underlying physics engine, as I assume Box2d doesn't know anything about Collider2D (Unity class) but only some convex collider shapes, so I suspect would have already returned a list of convex shapes or edges hit by the shape cast (or probably a contact manifold; I'm not familiar enough with Box2d).

    Is there any chance to get those multiple hit points exposed? Maybe just return an array of them. Or maybe make it such that shape casts return the list of sub-colliders hit inside the CompoundCollider2D, and not the compound itself. Indeed the compound will be hit all the time assuming a single Tilemap representing the game world, which typically spans a very large part of the 2D world so isn't of much interest (the caller generally wants to know what happens in the vicinity of the physics query, not on the other side of the world).

    Thanks
     

    Attached Files: