I’m trying the physics in JMonkey with a simple example of a lot of balls bouncing and colliding with each other and the floor.
The problem is that many balls never come to a stop: they keep rolling down the floor. Why? How should I make them stop in a realistic way?
I’ve set the friction and restitution of both the floor and the balls and tried different values.
This is the complete code of the example:
[java]package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
public class HelloBouncingBalls extends SimpleApplication {
public static void main(String[] args) {
HelloBouncingBalls app = new HelloBouncingBalls();
app.start();
}
/**
* Prepare the Physics Application State (jBullet)
*/
private BulletAppState bulletAppState;
/**
* Prepare geometries and physical nodes for the floor and the balls.
*/
private RigidBodyControl ball_phy;
private static final Sphere ball;
private RigidBodyControl floor_phy;
private static final Box floor;
static {
/**
* Initialize the ball geometry
*/
ball = new Sphere(16, 16, 0.3f, true, false);
ball.setTextureMode(TextureMode.Projected);
/**
* Initialize the floor geometry
*/
floor = new Box(100f, 1f, 100f);
floor.scaleTextureCoordinates(new Vector2f(6, 6));
}
@Override
public void simpleInitApp() {
/**
* Set up Physics Game
*/
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0f,-9.81f,0f));
//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
/**
* Configure cam to look at scene
*/
cam.setLocation(new Vector3f(0, 5, -10));
cam.lookAt(new Vector3f(0, 2, 0), Vector3f.UNIT_Y);
/**
* Initialize the scene, materials, and physics space
*/
initBalls();
initFloor();
}
/**
* Make a solid floor and add it to the scene.
*/
public void initFloor() {
Material floor_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TextureKey key3 = new TextureKey("Textures/Terrain/Pond/Pond.jpg");
key3.setGenerateMips(true);
Texture tex3 = assetManager.loadTexture(key3);
tex3.setWrap(WrapMode.Repeat);
floor_mat.setTexture("ColorMap", tex3);
Geometry floor_geo = new Geometry("Floor", floor);
floor_geo.setMaterial(floor_mat);
floor_geo.setLocalTranslation(0, -0.1f, 0);
this.rootNode.attachChild(floor_geo);
/* Make the floor physical with mass 0.0f! */
floor_phy = new RigidBodyControl(0.0f);
floor_geo.addControl(floor_phy);
bulletAppState.getPhysicsSpace().add(floor_phy);
/* Floor physical properties */
floor_phy.setRestitution(0.7f);
floor_phy.setFriction(1f);
}
/**
* This loop builds a lot of balls.
*/
public void initBalls() {
for (int j = 0; j < 10; j++) {
for (int i = -5; i < 5; i++) {
Vector3f vt = new Vector3f(i * 2, 10, j * 2);
makeBall(vt);
}
}
}
/**
* This method creates one individual ball.
*/
public void makeBall(Vector3f loc) {
/**
* Create a ball geometry and attach to scene graph.
*/
Material ball_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
ball_mat.setColor("Color", ColorRGBA.randomColor());
Geometry ball_geo = new Geometry("ball", ball);
ball_geo.setMaterial(ball_mat);
rootNode.attachChild(ball_geo);
/**
* Make ball physical with a mass > 0.0f.
*/
ball_phy = new RigidBodyControl(1f);
/**
* Add physical ball to physics space.
*/
ball_geo.addControl(ball_phy);
bulletAppState.getPhysicsSpace().add(ball_phy);
/* Set an initial velocity */
ball_phy.setLinearVelocity(new Vector3f(FastMath.rand.nextFloat()-0.5f,
FastMath.rand.nextFloat(), FastMath.rand.nextFloat()-0.5f));
/* Set physical properties */
ball_phy.setRestitution(0.6f);
ball_phy.setFriction(1f);
ball_phy.setSleepingThresholds(1f, 1f);
/* Set location */
ball_phy.setPhysicsLocation(loc);
}
}[/java]