Improve collision event support for common scenarios (minimal "kinematic bodies" support) #877
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR allows static bodies to collide with each other, on the condition that at least one of the two is a sensor. It also allows static bodies to collide with sleeping bodies, though the latter won't automatically wake on such a collision. (They can just be woken in the collision event if needed; I do think it might be more intuitive for non-sensor static bodies to wake sleeping bodies automatically, but I'm not sure if that might carry undesirable side effects.)
Rationale
In games, even ones where gameplay is heavily driven by physics, it's often desirable to have full control over some physics bodies by removing the effect of simulation forces like gravity, drag, inertia, etc. on them. Some motion in games is highly unrealistic, so "doing one's own bookkeeping" on certain bodies can be more simple, predictable, and easy for designers to tweak than trying to wrestle with simulation properties. For example, in a game like Super Mario Bros you may want to limit terminal velocity to an explicit, fairly low value to allow players a chance to react even if they drop from a great height; or if the player bounces off a turtle you might not want to transfer momentum in a typical way.
That said, it's also often desirable for these manually-controlled bodies to continue to participate in the simulation in some way. If a simulation-driven rock falls on a character we may want them to take damage or otherwise react in some way; characters with skeletal animation may "ragdoll" and allow the simulation to dictate their motion. At a more basic level, it's useful to be able to reuse existing collision systems, events, and idioms rather than implement additional detection, spatial partitioning, etc., for this other class of objects.
Box2D, PhysX and other physics engines usually refer to this type of body as "kinematic," and it's one of the most upvoted issues for this repo. But Matter already has something very similar in
isStatic
: manually driving static bodies is very well-behaved, as the manipulation demo shows. The only thing missing is that currently only non-static bodies trigger events with static bodies, making it difficult to handle, say, the platform game case of anisStatic
player character jumping on anisStatic
enemy.This PR resolves this by allowing pairs of static bodies to be candidates on the broadphase grid, as long as at least one of them is a sensor. This seemed like a reasonable compromise between allowing the necessary affordances for kinematic control without incurring too much of a performance penalty (or, I hope, introducing any unexpected new collision behaviour). It also removes an early out case in
Detector.collisions
(afaict never hit because of the broadphase condition) preventing two static bodies from colliding, and resolves an edge case where there wasn't really a sensible way for static bodies to wake sleeping dynamic bodies (fixes #875).Alternatives
The Phaser game framework, which now bundles Matter, seems to suggest getting around the lack of static-on-static events by doing stuff like zeroing out gravity and setting inertia on bodies to infinity. This seems more inefficient -- since rather than telling the engine to not bother trying to apply forces, we're instead setting parameters high enough to make them moot -- and I worry it could lead to unexpected behaviour or simulation instability. It's also kind of inconvenient to have to zero out gravity and apply it ourselves, all else being equal.
Rather than making this new behaviour the default for static bodies, we could instead add a new per-body flag to opt-in to collisions with other static bodies. I think the "at least one sensor" approach of this PR is a good default, but a flag to allow a static body to collide with any other body (static or not, sensor or not) could still be useful on top of that. (Unity's 2D physics system, which is based on Box2D, has a per-body flag called "use full kinematic contacts" which does just this:)
Rather than apply this behaviour to
isStatic
bodies, we could introduce a new kinematic body type. This doesn't seem super necessary to me, but it might make sense if there was further optimization work done onisStatic
, such that it became a flag for bodies that were intended to never be moved or moved only infrequently. (It might also help alleviate some of the questions that come up in the issue tracker about kinematic bodies -- but updating demos or adding a bit more documentation could do that too.)Hope this is helpful discussion! Sorry for the wall of text for such a tiny PR.