简体   繁体   中英

How allow collision with a Distance joint in box2d

I have a series of particles attached by a Distance Joint (using Processing with box2d ). The particles have to be a certain size. I want to throw bricks at the chain of particles and for the bricks to bounce off. At the moment the bricks bounce off the particles but not the joint. How can I make them do so. My MCVE:

import shiffman.box2d.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.joints.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.contacts.*;
import org.jbox2d.particle.ParticleGroupDef;
import org.jbox2d.particle.ParticleSystem;
import org.jbox2d.particle.ParticleType;
import org.jbox2d.particle.ParticleDef;

import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
// A reference to our box2d world
Box2DProcessing box2d;
ParticleSystem particleSystem;
ParticleDef pd=new ParticleDef();
Bridge bridge;
int PARTICLES = 10; // the amount of particles in your bridge
 ParticleDef pdef=new ParticleDef();
// A list for all of our rectangles
ArrayList<Box> boxes;


void setup() {

  size(1040,1060);
  smooth();

  // Initialize box2d physics and create the world
  box2d = new Box2DProcessing(this);
  box2d.createWorld();
  // Make the bridge total length,number of points,x start position
  bridge = new Bridge(width,PARTICLES,200);
  // Create ArrayLists  
  boxes = new ArrayList<Box>();


}
void draw() {
   background(255);

  // We must always step through time!
  box2d.step();

  // When the mouse is clicked, add a new Box object
  if (mousePressed) {
    Box p = new Box(mouseX,mouseY);
    boxes.add(p);
  }



  // Display all the boxes
  for (Box b: boxes) {
    b.display();
  }

  // Boxes that leave the screen, we delete them (note they have to be deleted from both the box2d world and our list
  for (int i = boxes.size()-1; i >= 0; i--) {
    Box b = boxes.get(i);
    if (b.done()) {
      boxes.remove(i);
    }
  }

 bridge.display();

 fill(0);
       float move_1=300;
    for (int i=0; i<10; i++){
            bridge.particles.get(i).body.setTransform(box2d.coordPixelsToWorld(move_1+10,i*20+70), 0);
    }

}

// A rectangular box
class Box  {

  // We need to keep track of a Body and a width and height
  Body body;
  float w;
  float h;

  // Constructor
  Box(float x, float y) {
    w = random(4,16);
    h = random(4,16);
    // Add the box to the box2d world
    makeBody(new Vec2(x,y),w,h);
  }

  // This function removes the particle from the box2d world
  void killBody() {
    box2d.destroyBody(body);
  }

  // Is the particle ready for deletion?
  boolean done() {
    // Let's find the screen position of the particle
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Is it off the bottom of the screen?
    if (pos.y > height+w*h) {
      killBody();
      return true;
    }
    return false;
  }

  // Drawing the box
  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Get its angle of rotation
    float a = body.getAngle();

    rectMode(CENTER);
    pushMatrix();
    translate(pos.x,pos.y);
    rotate(-a);
    fill(175);
    stroke(0);
    rect(0,0,w,h);
    popMatrix();
  }

  // This function adds the rectangle to the box2d world
  void makeBody(Vec2 center, float w_, float h_) {

    // Define a polygon (this is what we use for a rectangle)
    PolygonShape sd = new PolygonShape();
    float box2dW = box2d.scalarPixelsToWorld(w_/2);
    float box2dH = box2d.scalarPixelsToWorld(h_/2);
    sd.setAsBox(box2dW, box2dH);

    // Define a fixture
    FixtureDef fd = new FixtureDef();
    fd.shape = sd;
    // Parameters that affect physics
    fd.density = 1;
    fd.friction = 300;
    fd.restitution = 0.0;

    // Define the body and make it from the shape
    BodyDef bd = new BodyDef();
    bd.type = BodyType.DYNAMIC;
    bd.position.set(box2d.coordPixelsToWorld(center));

    body = box2d.createBody(bd);
    body.createFixture(fd);
    // Give it some initial random velocity
   body.setLinearVelocity(new Vec2(random(-5, 5), random(2, 5)));

  }

}


// Series of Particles connected with distance joints

class Bridge {

  // Bridge properties
  float totalLength;  // How long
  int numPoints;      // How many points in a line
  int NewCurvepoints; // How many points in a curve for the top of the stomach
  // Our chain is a list of particles
  ArrayList<Particle> particles;

  // Chain constructor
  Bridge(float l, int n,int start) {

    totalLength = l;
    numPoints = n;
    NewCurvepoints=n;
    particles = new ArrayList();
    float len = totalLength / numPoints;

    // Add particles to the chain    
    for(int i=0; i < PARTICLES; i++) {
      // Make a new particle
      Particle p = null;     
      //x,y,radius,fixed
            p = new Particle(start,i*len,7,3);

      particles.add(p);
      if (i > 0) {
         DistanceJointDef djd = new DistanceJointDef();
         Particle previous = particles.get(i-1);
         djd.bodyA = previous.body;
         djd.bodyB = p.body;
         djd.length = box2d.scalarPixelsToWorld(len/40);
         line(djd.bodyA.getPosition().x,djd.bodyA.getPosition().y,djd.bodyB.getPosition().x,djd.bodyB.getPosition().y);
         djd.frequencyHz = 0;
         djd.dampingRatio = 0;
         DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd);
      }
    }

     }

 // // Draw the bridge
  void display() { for(int i=0; i < particles.size()-1; i++) {
    Vec2 pos1 = box2d.getBodyPixelCoord(particles.get(i).body);
    Vec2 pos2 = box2d.getBodyPixelCoord(particles.get(i+1).body);
    stroke(0);
    strokeWeight(2);
    line(pos1.x,pos1.y,pos2.x,pos2.y);
  }
    for (Particle p: particles) {
      p.display();
    }
  }

}

class Particle {

  // We need to keep track of a Body and a radius
  Body body;
  float r;

  color col;

  Particle(float x, float y, float r_, int fixed) {
    r = r_;    
    // Define a body
    BodyDef bd = new BodyDef();
    bd.fixedRotation=true;
    if (fixed==1) bd.type = BodyType.STATIC;
    else if (fixed==2) bd.type = BodyType.KINEMATIC;
    else if (fixed==3) bd.type = BodyType.DYNAMIC;

    // Set its position
    bd.position = box2d.coordPixelsToWorld(x,y);
    body = box2d.world.createBody(bd);

    // Make the body's shape a circle
    CircleShape cs = new CircleShape();
    cs.m_radius = box2d.scalarPixelsToWorld(r);

    FixtureDef fd = new FixtureDef();
    fd.shape = cs;
    // Parameters that affect physics
    fd.density = 0;
    fd.friction = 0;
    fd.restitution = -90;
    body.createFixture(fd);
    col = color(175);
    //determine how it moves
  }


  // 
  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Get its angle of rotation
    float a = body.getAngle();
    pushMatrix();
    translate(pos.x,pos.y);
    rotate(a);
    fill(col);
    stroke(0);
    strokeWeight(1);
    ellipse(0,0,r*2,r*2);
    // Let's add a line so we can see the rotation
    line(0,0,r,0);
    popMatrix();
  }


}

Answer:

You can't. Not exactly.

Joints do not participate in collision detection. So bodies cannot bounce off of joints themselves.

Stringing bodies together with joints in a way that left no gaps between bodies seems like it should ensure that a body cannot pass through that string of bodies. It does sometimes. But not always.

Additional Info:

Take the Bridge TestBed case for example. The bodies that fall onto the bridge (as part of the test) do bounce off of the bridge body pieces. They're connected by revolute joints. But if I use the Spacebar to launch a "bomb" at the bridge with enough force, it gets through the bodies that make-up the bridge. This happens even if I set the bridge body parts to being bullet bodies.

Here's a snap-shot close up of a "bomb" getting through the bridge:

炸弹通过桥梁测试

A segment of the bridge has gotten knocked out of place allowing the bomb to get through it.

A distance joint might do better than the revolute joint. I don't know that it will however.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM