0
\$\begingroup\$

I am working on a particle simulation using Box2D with Processing.

The setup: I generate 4 kinds of particles that exist in equal amounts (for instance 200 in total, 50 each). They are (for now) randomly moving inside a box, each edge of the box is made of a static boundary. The Particles should bounce off each other as well as all 4 boundaries. This works fine.

Now I am working with the collisionListeners.beginContact() function to make different things happen when different particles collide. My problem occurs in the following case: when two particles of the same kind collide, they should produce a particle of another kind at the location of their collision with an added velocity of their previous velocities. In most cases, this is working well! However, in about 15% of the cases, it does not: sometimes the new particle is not generated at the location of their collision, but at the world center point (0,0), or rather at the center of the processing canvas if speaking in pixels (width/2,height/2). This results in particles randomly shooting out of the center point of the canvas, which is not what I want. And even worse, they tend to stack up on top of each other causing errors.

I do not know why this is happening, I am suspecting it might have something to do with collisions that happen very close to the boundaries so that there is some kind of tunnelling effect that teleports them to the center? But I have no real clue...

I am getting the location of the collision inside beginContact() through this process:

// assign objects to colliding particles
  Fixture f1 = c.getFixtureA();
  Fixture f2 = c.getFixtureB();
  Body b1 = f1.getBody();
  Body b2 = f2.getBody();
  Object o1 = b1.getUserData();
  Object o2 = b2.getUserData();
// get velocity for new particle
  Vec2 velB1 = b1.getLinearVelocity();
  Vec2 velB2 = b2.getLinearVelocity();
  Vec2 addedVel = velB1.add(velB2);
// get collision coordinates in pixel values
  WorldManifold worldManifold = new WorldManifold ();
  c.getWorldManifold(worldManifold);
  Vec2 collPointPx = box2d.coordWorldToPixels(worldManifold.points[0]);

The last vector collPointPx is the one I am using when generating the new particle, and it is the vector that apparently every now and then shows (0,0) or rather (width/2,height/2) instead of the right location of the collision.

It would be great if anyone of you has an idea how to solve this. Maybe I am making a mistake in the code posted. Obviously, I am a beginner at this. Thank you very much!

\$\endgroup\$
4
  • \$\begingroup\$ Are your particles circular? If so, you may want to use just a weighted average of the particle positions, rather than counting on the collision manifold containing the exact point you want. (For Box2D's purposes, the manifold just has to contain information that leads to the right restitution impulses, even if the points are outside the objects, or even undefined for some collision corner-case) \$\endgroup\$
    – DMGregory
    Mar 1 at 16:24
  • \$\begingroup\$ Hey, thank you for your reply! Yes, my particles are circular. I think this can be a helpful clue, I did not know that the manifold does not necessarily always contain the exact point of collision. Maybe it can work if I calculate the center of a line between the particles and use that point as the origin for the new particle? Or how would you get a weighted average of the particles positions? \$\endgroup\$
    – wo_ste
    Mar 1 at 18:15
  • \$\begingroup\$ A weighted average IS a point on that line. The center point is the case when the weights are equal. If your particles have non-equal radii, then you might want to use those radii as the weights, so that the spawn point is closer to the smaller particle and farther from the larger one. \$\endgroup\$
    – DMGregory
    Mar 1 at 18:29
  • \$\begingroup\$ Thank you, this makes sense, I was first confused by the weights. It works!! :-) Great hint regarding the manifold. I checked it carefully and you were right, sometimes it was even NaN. \$\endgroup\$
    – wo_ste
    Mar 1 at 20:55

1 Answer 1

1
\$\begingroup\$

The comments of DMGregory helped me out. I was using points from the collisions worldManifold, but they do not necessarily contain the exact location of the collision between two particles.

I solved it by subtracting the particle locations (bigger - smaller) and adding half of the result to the smaller one. This results in the center of a line drawn between them. As DMGregory pointed out, it makes sense to add some shift / weights to the point on this line, if the particles are not the same size.

// get collision coordinates in pixel values
    Vec2 posB1 = box2d.getBodyPixelCoord(b1);
    Vec2 posB2 = box2d.getBodyPixelCoord(b2);
    if ((posB1.x + posB1.y) > (posB2.x + posB2.y)) {
      collPointPx = new Vec2 ((posB2.x+((posB1.x-posB2.x)/2)), (posB2.y+((posB1.y-posB2.y)/2)));
    } else {
      collPointPx = new Vec2 ((posB1.x+((posB2.x-posB1.x)/2)), (posB1.y+((posB2.y-posB1.y)/2)));
    }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .