Hi,
I’m testing JME and Jbullet and I have some trouble reproducing the HelloCollision tutorial with a box instead of the “SceneModel”. I created a box “floor” and a box “brick”, the brick fall correctly on the floor, but my CapsuleCollisionShape fall through with a println message : “warning CollisionDispatcher.needsCollision: static-static collision!”
I also tested with making a BoxCollisionShape for the floor and it didn’t work.
Here’s the code, sorry for the mess :
[java] bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
// The falling brick
Box brick_shape = new Box(1, 1, 1);
Geometry brick = new Geometry(“Brick”, brick_shape);
Material brick_mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);
brick_mat.setColor(“Color”, ColorRGBA.Red);
brick.setMaterial(brick_mat);
brick.setLocalTranslation(0, 30, 0);
// brick phy
brick_phy = new RigidBodyControl(3);
brick.addControl(brick_phy);
// The floor
Box floor_shape = new Box(Vector3f.ZERO, 2f, 0.1f, 2f);
floor = new Geometry(“floor”, floor_shape);
Material floor_mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);
floor_mat.setColor(“Color”, ColorRGBA.Blue);
floor.setMaterial(floor_mat);
// floor phy
floor_phy = new RigidBodyControl(0);
floor.addControl(floor_phy);
// The capsule phy
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
player_phy = new CharacterControl(capsuleShape, 0.05f);
player_phy.setJumpSpeed(20);
player_phy.setFallSpeed(10);
player_phy.setGravity(30);
player_phy.setPhysicsLocation(new Vector3f(0, 10, 0));
// Attachment
rootNode.attachChild(floor);
rootNode.attachChild(brick);
bulletAppState.getPhysicsSpace().add(floor_phy);
bulletAppState.getPhysicsSpace().add(brick_phy);
bulletAppState.getPhysicsSpace().add(player_phy);[/java]
Thanks, can you make that a complete test case class please then I can check, from just looking the code looks ok.
Here is the entire code. Thanks in advance.
[java]package firstSteps;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
public class Runner extends SimpleApplication implements ActionListener {
public static void main(String[] args){
Runner app = new Runner();
app.start();
}
private BulletAppState bulletAppState;
private Geometry floor;
private RigidBodyControl floor_phy;
private RigidBodyControl brick_phy;
private CharacterControl player_phy;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, foreward = false, backward = false;
public void simpleInitApp() {
/** Set up Physics /
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
// We re-use the flyby camera for rotation, while positioning is handled by physics
viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
setUpKeys();
setUpLight();
// The falling brick
Box brick_shape = new Box(1, 1, 1);
Geometry brick = new Geometry("Brick", brick_shape);
Material brick_mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
brick_mat.setColor("Color", ColorRGBA.Red);
brick.setMaterial(brick_mat);
brick.setLocalTranslation(0, 30, 0);
// brick phy
brick_phy = new RigidBodyControl(3);
brick.addControl(brick_phy);
// The floor
Box floor_shape = new Box(Vector3f.ZERO, 2f, 0.1f, 2f);
floor = new Geometry("floor", floor_shape);
Material floor_mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
floor_mat.setColor("Color", ColorRGBA.Blue);
floor.setMaterial(floor_mat);
// floor phy
floor_phy = new RigidBodyControl(0);
floor.addControl(floor_phy);
// Attachment
rootNode.attachChild(floor);
rootNode.attachChild(brick);
bulletAppState.getPhysicsSpace().add(floor_phy);
bulletAppState.getPhysicsSpace().add(brick_phy);
}
private void setUpLight() {
// We add a light so we see the scene
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White.clone().multLocal(2)); // bright white light
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalize());
rootNode.addLight(dl);
}
/* We over-write some navigational key mappings here, so we can
- add physics-controlled walking and jumping: /
private void setUpKeys() {
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_Q));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_Z));
inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("ActiveCam", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT) );
inputManager.addListener(this, "Left");
inputManager.addListener(this, "Right");
inputManager.addListener(this, "Forward");
inputManager.addListener(this, "Backward");
inputManager.addListener(this, "Jump");
}
/* These are our custom actions triggered by key presses.
- We do not walk yet, we just keep track of the direction the user pressed. */
public void onAction(String binding, boolean value, float tpf) {
if (binding.equals("Left")) {
if (value) { left = true; } else { left = false; }
} else if (binding.equals("Right")) {
if (value) { right = true; } else { right = false; }
} else if (binding.equals("Foreward")) {
if (value) { foreward = true; } else { foreward = false; }
} else if (binding.equals("Backward")) {
if (value) { backward = true; } else { backward = false; }
} else if (binding.equals("Jump")) {
player_phy.jump();
}
}
/**
- This is the main event loop–walking happens here.
- We check in which direction the player is walking by interpreting
- the camera direction forward (camDir) and to the side (camLeft).
- The setWalkDirection() command is what lets a physics-controlled player walk.
- We also make sure here that the camera moves with player.
*/
@Override
public void simpleUpdate(float tpf) {
Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
walkDirection.set(0, 0, 0);
if (left) { walkDirection.addLocal(camLeft); }
if (right) { walkDirection.addLocal(camLeft.negate()); }
if (foreward) { walkDirection.addLocal(camDir); }
if (backward) { walkDirection.addLocal(camDir.negate()); }
player_phy.setWalkDirection(walkDirection);
cam.setLocation(player_phy.getPhysicsLocation());
}}
[/java]
Hm, I can confirm this but I don’t quite get why bullet spawns that message, its only concave vs convex shapes… Anyway for large triangles in relation to the character the mesh collision shape is not very suited, you should use a box or plane collision shape. For normal meshes I cannot reproduce this.
Edit: Looked in the bullet source and the warning is nothing serious…
Thanks for your answer. I realize that in my complete code, I forgot the declaration of the Player phy caspuleShape. Hope you’ve noticed.
Anyway for large triangles in relation to the character the mesh collision shape is not very suited, you should use a box or plane collision shape. For normal meshes I cannot reproduce this.
Can you explain this? because I am beginner and I don't know why you're talking about triangles. I don't even know the difference between mesh collision shape and box or plane collision shape. I thought the seconds where subclasses of the first.
Thanks for your help
Yes, I noticed. Physics for simple shapes is computed based on shape primitives like sphere, box etc. When you use a Mesh to compute the collisions its more complicated. When you use the RigiBodyControl(float mass) constructor, a mesh collision shape is generated based on the visual mesh.
OKay thank you for the answer. If I understand well, all the jme3.bullet.control package implements PhysicsControl. In this package I see Character, Ghost, RagDoll, RigidBody and Vehicule Controls. I understand that the RigidBodyControl creates a mesh from my simple box shape and that cause problem.
But, If I can’t use RigidBodyControl, what object should I instance to compute collision between my CharacterControl and a simple shape like my cube?
BTW, I don’t really understand the diference between a shape and a mesh.
Sorry for my noobying If these answers are in the advanced tutorials so tell me, I didn’t read them cause I’m not an advanced user
A collision shape is what the physics needs to tell where and how collision happens. A mesh is a list of vertexes that make up some model consisting of triangles mostly. Thus a collision shape can be defined by “sphere with radius x” while a mesh cannot.
To use another type of collision shape do it like this:
[java]
floor_phy = new RigidBodyControl(new BoxCollisionShape(new Vector3f(2,0.1f,2)),0);
[/java]
I understand the problem with the mesh. Then I tried your writting : create a box shape as collision control instead of letting the RigidBodyControl create a complex Mesh. But I stille fall trought my floor, and my brick still react correctly.
Does the capsule mesh is a problem to?
Here is the code. Thanks again for the time you spend on my problem.
[java]package firstSteps;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
public class Runner extends SimpleApplication implements ActionListener {
public static void main(String[] args){
Runner app = new Runner();
app.start();
}
private BulletAppState bulletAppState;
private Geometry floor;
private RigidBodyControl floor_phy;
private RigidBodyControl brick_phy;
private CharacterControl player_phy;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, foreward = false, backward = false;
public void simpleInitApp() {
/** Set up Physics /
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
// We re-use the flyby camera for rotation, while positioning is handled by physics
viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
setUpKeys();
setUpLight();
// The falling brick
Box brick_shape = new Box(1, 1, 1);
Geometry brick = new Geometry("Brick", brick_shape);
Material brick_mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
brick_mat.setColor("Color", ColorRGBA.Red);
brick.setMaterial(brick_mat);
brick.setLocalTranslation(0, 30, 0);
// brick phy
brick_phy = new RigidBodyControl(new BoxCollisionShape(new Vector3f(1, 1, 1)), 3);
brick.addControl(brick_phy);
// The floor
Box floor_shape = new Box(Vector3f.ZERO, 2f, 0.1f, 2f);
floor = new Geometry("floor", floor_shape);
Material floor_mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");
floor_mat.setColor("Color", ColorRGBA.Blue);
floor.setMaterial(floor_mat);
// floor phy
floor_phy = new RigidBodyControl(new BoxCollisionShape(new Vector3f(2f, 0.1f, 2f)), 0);
floor.addControl(floor_phy);
// The capsule phy
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
player_phy = new CharacterControl(capsuleShape, 0.05f);
player_phy.setJumpSpeed(20);
player_phy.setFallSpeed(10);
player_phy.setGravity(30);
player_phy.setPhysicsLocation(new Vector3f(0, 10, 0));
// Attachment
rootNode.attachChild(floor);
rootNode.attachChild(brick);
bulletAppState.getPhysicsSpace().add(floor_phy);
bulletAppState.getPhysicsSpace().add(brick_phy);
bulletAppState.getPhysicsSpace().add(player_phy);
}
private void setUpLight() {
// We add a light so we see the scene
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White.clone().multLocal(2)); // bright white light
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalize());
rootNode.addLight(dl);
}
/* We over-write some navigational key mappings here, so we can
- add physics-controlled walking and jumping: /
private void setUpKeys() {
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_Q));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Foreward", new KeyTrigger(KeyInput.KEY_Z));
inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("ActiveCam", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addListener(this, "Left");
inputManager.addListener(this, "Right");
inputManager.addListener(this, "Foreward");
inputManager.addListener(this, "Backward");
inputManager.addListener(this, "Jump");
}
/* These are our custom actions triggered by key presses.
- We do not walk yet, we just keep track of the direction the user pressed. */
public void onAction(String binding, boolean value, float tpf) {
if (binding.equals("Left")) {
if (value) { left = true; } else { left = false; }
} else if (binding.equals("Right")) {
if (value) { right = true; } else { right = false; }
} else if (binding.equals("Foreward")) {
if (value) { foreward = true; } else { foreward = false; }
} else if (binding.equals("Backward")) {
if (value) { backward = true; } else { backward = false; }
} else if (binding.equals("ActiveCam")) {
} else if (binding.equals("Jump")) {
player_phy.jump();
}
}
/**
- This is the main event loop–walking happens here.
- We check in which direction the player is walking by interpreting
- the camera direction forward (camDir) and to the side (camLeft).
- The setWalkDirection() command is what lets a physics-controlled player walk.
- We also make sure here that the camera moves with player.
*/
@Override
public void simpleUpdate(float tpf) {
Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
walkDirection.set(0, 0, 0);
if (left) { walkDirection.addLocal(camLeft); }
if (right) { walkDirection.addLocal(camLeft.negate()); }
if (foreward) { walkDirection.addLocal(camDir); }
if (backward) { walkDirection.addLocal(camDir.negate()); }
player_phy.setWalkDirection(walkDirection);
cam.setLocation(player_phy.getPhysicsLocation());
}}
[/java]
Hi, I got new data after some tests.
I’ve tested some different Collision Shape and it’s very strange to me :
floor = boxCollisionShape & player = boxCollisionShape => fall through
floor = boxCollisionShape & player = boxCollisionShape & player.gravity = 0 => Seem to be maintain by the bottom of the floor (clipping bug) but not falling trough
floor = boxCollisionShape & player = capsuleCollisionShape => fall through
but,
floor = mesh with “CollisionShapeFactory.createMeshShape()” & player = sphereCollisionShape => Work Perfectly
floor = boxCollisionShape & player = sphereCollisionShape => fall through “slowly” : I stop my falling on the floor, but slowly get down like in mouving sands, and finaly go through (Strange, isn’t it?)
Do you have any rational explanation? The big thing that I d’ont understand is the difference between my code and the different tutorial code. What’s the problem with me?
Here is the code of the mouving sands sollution, with the other in //comments
[java]package firstSteps;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
public class Runner extends SimpleApplication implements ActionListener {
public static void main(String[] args){
Runner app = new Runner();
app.start();
}
private BulletAppState bulletAppState;
private Geometry floor;
private RigidBodyControl floor_phy;
private RigidBodyControl brick_phy;
private CharacterControl player_phy;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, foreward = false, backward = false;
public void simpleInitApp() {
/** Set up Physics /
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
// We re-use the flyby camera for rotation, while positioning is handled by physics
viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
setUpKeys();
setUpLight();
flyCam.setDragToRotate(true);
// The falling brick
Box brick_shape = new Box(1, 1, 1);
Geometry brick = new Geometry(“Brick”, brick_shape);
Material brick_mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);
brick_mat.setColor(“Color”, ColorRGBA.Red);
brick.setMaterial(brick_mat);
brick.setLocalTranslation(10, 30, 0);
// brick phy
brick_phy = new RigidBodyControl(new BoxCollisionShape(new Vector3f(1, 1, 1)), 3);
brick.addControl(brick_phy);
// The floor
Box floor_shape = new Box(Vector3f.ZERO, 20f, 0.1f, 20f);
floor = new Geometry(“floor”, floor_shape);
Material floor_mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);
floor_mat.setColor(“Color”, ColorRGBA.Blue);
floor.setMaterial(floor_mat);
// floor phy
floor_phy = new RigidBodyControl(new BoxCollisionShape(new Vector3f(20f, 0.1f, 20f)), 0);
//floor_phy = new RigidBodyControl(CollisionShapeFactory.createMeshShape(floor), 0);
floor.addControl(floor_phy);
// The capsule phy
//player_phy = new CharacterControl(new CapsuleCollisionShape(1.5f, 6f), 0.05f);
//player_phy = new CharacterControl(new BoxCollisionShape(new Vector3f(1, 1, 1)), 0.05f);
player_phy = new CharacterControl(new SphereCollisionShape(5), .01f);
player_phy.setJumpSpeed(20);
player_phy.setFallSpeed(30);
player_phy.setGravity(30);
player_phy.setPhysicsLocation(new Vector3f(0, 10, 0));
// Attachment
rootNode.attachChild(floor);
rootNode.attachChild(brick);
bulletAppState.getPhysicsSpace().add(floor_phy);
bulletAppState.getPhysicsSpace().add(brick_phy);
bulletAppState.getPhysicsSpace().add(player_phy);
}
private void setUpLight() {
// We add a light so we see the scene
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White.clone().multLocal(2)); // bright white light
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalize());
rootNode.addLight(dl);
}
/* We over-write some navigational key mappings here, so we can
- add physics-controlled walking and jumping: /
private void setUpKeys() {
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_Q));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Foreward", new KeyTrigger(KeyInput.KEY_Z));
inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("ActiveCam", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addListener(this, "Left");
inputManager.addListener(this, "Right");
inputManager.addListener(this, "Foreward");
inputManager.addListener(this, "Backward");
inputManager.addListener(this, "Jump");
}
/* These are our custom actions triggered by key presses.
- We do not walk yet, we just keep track of the direction the user pressed. */
public void onAction(String binding, boolean value, float tpf) {
if (binding.equals("Left")) {
if (value) { left = true; } else { left = false; }
} else if (binding.equals("Right")) {
if (value) { right = true; } else { right = false; }
} else if (binding.equals("Foreward")) {
if (value) { foreward = true; } else { foreward = false; }
} else if (binding.equals("Backward")) {
if (value) { backward = true; } else { backward = false; }
} else if (binding.equals("ActiveCam")) {
} else if (binding.equals("Jump")) {
player_phy.jump();
}
}
/**
- This is the main event loop–walking happens here.
- We check in which direction the player is walking by interpreting
- the camera direction forward (camDir) and to the side (camLeft).
- The setWalkDirection() command is what lets a physics-controlled player walk.
- We also make sure here that the camera moves with player.
*/
@Override
public void simpleUpdate(float tpf) {
Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
camDir.y = 0;
camLeft.y = 0;
walkDirection.set(0, 0, 0);
if (left) { walkDirection.addLocal(camLeft); }
if (right) { walkDirection.addLocal(camLeft.negate()); }
if (foreward) { walkDirection.addLocal(camDir); }
if (backward) { walkDirection.addLocal(camDir.negate()); }
player_phy.setWalkDirection(walkDirection);
cam.setLocation(player_phy.getPhysicsLocation());
}}
[/java]
I land on the floor when I use this:
I guess the problem is you try to tweak the fall speed etc. because your capsule is pretty large and seems to fall “slow”. But remember this capsule is six meters high!
[java]
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(2.5f, 6f, 1);
player_phy = new CharacterControl(capsuleShape, 0.1f);
player_phy.setJumpSpeed(20);
player_phy.setFallSpeed(10);
//note that I dont set the gravity
//player_phy.setGravity(30);
player_phy.setPhysicsLocation(new Vector3f(0, 10, 0));
bulletAppState.getPhysicsSpace().add(player_phy);
Box floor_shape = new Box(Vector3f.ZERO, 2f, 1.1f, 2f);
floor = new Geometry(“floor”, floor_shape);
Material floor_mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);
floor_mat.setColor(“Color”, ColorRGBA.Blue);
floor.setMaterial(floor_mat);
floor.setLocalTranslation(0,-10,0);
floor_phy = new RigidBodyControl( 0);
floor.addControl(floor_phy);
rootNode.attachChild(floor);
bulletAppState.getPhysicsSpace().add(floor_phy);
[/java]