The main class for building a World where boxes are dropping on a flat surface. A SimpleSpace is attached for collision detection. The things to be implemented are HashSpace, box-box and box-plane collisions, and a Dantzig LCP constraint solver.
package simulator;
import javax.vecmath.*;
import java.awt.event.*;
import com.brackeen.javagamebook.input.*;
import java.util.List;
import java.util.LinkedList;
public class BoxStack
extends Simulator {
private class MyObject {
Body body; // the body
Geom geom; // geometries representing this body
};
private static final int NUM = 10;
private static final double DENSITY = 5.0;
private static final int MAX_CONTACTS = 4; // maximum number of contact points per body
private static MyObject[] obj;
private static int num = 0;
private static int nextobj = 0;
private static boolean random_pos = true;
private static World world;
private static Geom floor;
private List contactgroup;
protected GameAction fire
= new GameAction("fire", GameAction.DETECT_INITAL_PRESS_ONLY);
private class BoxStackCollision
extends Collision implements ContactConstants {
public void nearCallback(Geom g1, Geom g2) {
// exit without doing anything if the two bodies are connected by a joint
Body b1 = g1.getBody();
Body b2 = g2.getBody();
if (b1!=null && b2!=null &&
b1.isConnectedExcluding(b2,"simulator.ContactJoint")) return;
Contact[] contact = new Contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box
for (int i = 0; i < MAX_CONTACTS; i++) {
contact[i] = new Contact();
contact[i].surface.mode = Bounce | SoftCFM;
contact[i].surface.mu = Double.POSITIVE_INFINITY;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
int numc = collide(g1, g2, MAX_CONTACTS, contact);
if (numc > 0) {
for (int i = 0; i < numc; i++) {
Joint c = new ContactJoint(world, contact[i]);
c.attach(b1, b2);
}
}
}
}
public static void main(String[] args) {
new BoxStack().run();
}
public void start() {
inputManager.mapToKey(fire, KeyEvent.VK_SPACE);
inputManager.mapToMouse(fire, InputManager.MOUSE_BUTTON_1);
world = new World();
//space = new SimpleSpace(null);
contactgroup = new LinkedList();
obj = new MyObject[NUM];
for (int i = 0; i < NUM; i++) {
obj[i] = new MyObject();
}
world.setGravity(0, -0.5, 0);
world.setCFM(1e-5);
world.setAutoDisableFlag(true);
world.setContactMaxCorrectingVel(0.1);
world.setContactSurfaceLayer(0.001);
floor = new Plane(space, 0, 1, 0, 0);
space.setCollision(new BoxStackCollision());
}
public void step() {
//floor.setState(Geom.STATE_IDLE);
command();
space.collide();
world.step();
}
public void command() {
int i;
if (fire.isPressed()) {
if (num < NUM) {
i = num;
num++;
}
else {
i = nextobj;
nextobj++;
if (nextobj >= num) {
nextobj = 0;
}
}
obj[i].body = new Body(world);
double[] sides = new double[3];
for (int k = 0; k < 3; k++) {
sides[k] = Math.random() * 50 + 10;
}
Matrix3d R = new Matrix3d();
if (random_pos) {
obj[i].body.setPosition(Math.random() * 20 - 100,
Math.random() + 200,
Math.random() * 20 - 200);
R.set(new AxisAngle4d(Math.random() * 2.0 - 1.0,
Math.random() * 2.0 - 1.0,
Math.random() * 2.0 - 1.0,
Math.random() * 10.0 - 5.0));
}
else {
double maxheight = 0;
for (int k = 0; k < num; k++) {
Vector3d pos = obj[k].body.getPosition();
if (pos.z > maxheight) {
maxheight = pos.z;
}
}
obj[i].body.setPosition(0, maxheight + 1, 0);
R.set(new AxisAngle4d(0, 1, 0, Math.random() * 10.0 - 5.0));
}
obj[i].body.setRotation(R);
//dBodySetData (obj[i].body,(void*) i);
Mass m = new Mass();
m.setBox(DENSITY, sides[0], sides[1], sides[2]);
obj[i].geom = new Box(space, sides[0], sides[1], sides[2]);
obj[i].geom.setBody(obj[i].body);
obj[i].body.setMass(m);
}
}
}
Comments