liabru / matter-js

a 2D rigid body physics engine for the web ▲● ■
MIT License
16.87k stars 1.96k forks source link

How to recreate box2d's `collideConnected` option? (i.e. make bodies which share a constraint not collide) #1222

Open phunanon opened 1 year ago

phunanon commented 1 year ago

I have asked this question on StackOverflow also.

I can see that box2d has within its definition an option called collideConnected. This is false by default, causing bodies which are connected together to collide. How do I recreate the flag being true in matter-js?

For example, in the chains demo, the chamfer chain has overlapping links which collide with no other links in the chain. But I'd like for each link to be able to collide with any other link except its 1-2 neighbouring links.

By woefully hacking Detector.collisions I have managed to recreate this, by naively iterating through all world constraints to see if the two bodies share a constraint, but there might already be a better way?

Kibergx commented 1 year ago

I am new with this lib, but my only idea is to manually set the collusionFilter for every body (https://brm.io/matter-js/docs/classes/Body.html#property_collisionFilter.category). 32 is the maximum unique collision category.

Or if you decide to manipulate the source code I would expand the collusionFilter mechanics. Maybe I would add a callback function to it, if that function is declared then every time it checks the collusionFilter between two bodies the return value of the callback would decide (for example collusionFilter.onCanCollide). There is function, Detector.canCollide (https://github.com/liabru/matter-js/blob/ce03208c5f597d4a5bceaf133cc959c428dd5147/src/collision/Detector.js#L148) which decides if two body can collide with each other. So, maybe you add an index value to your chains, and create this callback function in the collusion filter which will decide if the two chain body can collide based on the index.

phunanon commented 1 year ago

Thanks for your response :)
I'm aware that using categories and masks would solve the issue up to 32 links, but it's a no-go for my use-case unfortunately. At the moment, I can't see a way of doing it without patching the collision logic.
I picked Detector.collisions to have access to the bodies for my testing, but yes, Detector.canCollide could make use of some enhanced filters. How matter-js works internally, and what the most performant/appropriate approach would be, I do not know. I think I might have to use my own patched version for moving forward, hoping that this issue sees some light!

MLH-AIDS commented 1 year ago

In my game, I made a way to create a complex (like a wheel) and set them up with the same "nextgroup", I don't know if it works for you

phunanon commented 1 year ago

Unfortunately, @MLH-AIDS, using the same nextGroup(true) (non-colliding) group causes all bodies to not collide with one another. I'm looking for a solution which only causes immediately constrained bodies to not collide, not whole groups of constrained bodies.

SnowdenWintermute commented 1 year ago

Did you ever figure out how to solve this? I am facing a similar issue. My current idea is to make all the bodies sensors and manually handle each collision. In the collision handling I could check if the bodies share a constraint. Did you come up with a better way?

EDIT: I think I have a working solution for my use case.

Problem:

Solution:

  1. Make the weapon bodies sensors by setting their isSensor property to true
  2. Listen for all collision events by setting up a listener on the engine.world:
    const physicsEngine = Matter.Engine.create()
    Matter.Events.on(physicsEngine, "collisionStart", (e) => handleCollision(e));
  3. In the handleCollision function we will now get collision pairs from our sensors when they occupy the same space as another body. These pairs will contain an isSensor property. It will be true if one of the bodies in the pair is a sensor, but this is a different property than the isSensor property on the body. It is the isSensor property of the pair.
  4. Turn off the isSensor property of each collision pair which meets the requirements of a collision we want to behave as normal. For your use case you could check if the body.id properties of the bodies in the pair are bodies which share a constraint. If they don't, then turn off isSensor for that pair.