Hey,
I am trying to create my own CharacterControl using sweeptests, but the sweeptest will sometimes not report a collision.
testcase:
[java]package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.PhysicsSweepTestResult;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.system.AppSettings;
import java.util.List;
public class Main extends SimpleApplication {
private BulletAppState bulletAppState;
public static void main(String[] args) {
Main app = new Main();
AppSettings settings = new AppSettings(true);
settings.setFrameRate(100);
app.start();
}
private CapsuleCollisionShape playerShape;
private Node playerNode;
@Override
public void simpleInitApp() {
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
Node geoNode = new Node("geometries");
rootNode.attachChild(geoNode);
Box b = new Box(new Vector3f(-5f, 0, 0), 1, 1, 1);
Geometry geom = new Geometry("Box1", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
geoNode.attachChild(geom);
Box b2 = new Box(Vector3f.ZERO.add(6f, 0, 0), 1, 3, 1);
Geometry geom2 = new Geometry("Box2", b2);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Red);
geom2.setMaterial(mat2);
geoNode.attachChild(geom2);
Box floor = new Box(new Vector3f(0, -3f, 0), 16f, 0.5f, 16f);
Geometry floorGeo = new Geometry("Floor", floor);
Material floorMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
floorMat.setColor("Color", ColorRGBA.Green);
floorGeo.setMaterial(floorMat);
geoNode.attachChild(floorGeo);
Sphere s = new Sphere(5, 5, 1);
Geometry sGeo = new Geometry("Sphere", s);
sGeo.setLocalTranslation(1f, 0f, 3f);
Material sMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
sMat.setColor("Color", ColorRGBA.Orange);
sGeo.setMaterial(sMat);
geoNode.attachChild(sGeo);
RigidBodyControl coll = new RigidBodyControl(0.0f);
geoNode.addControl(coll);
bulletAppState.getPhysicsSpace().add(coll);
playerNode = new Node("Player");
playerShape = new CapsuleCollisionShape(1.2f, 3f);
GhostControl playerGhost = new GhostControl(playerShape);
playerNode.addControl(playerGhost);
rootNode.attachChild(playerNode);
flyCam.setMoveSpeed(0.0f);
inputManager.addMapping("forward", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addListener(anlistener, "forward", "back", "left", "right");
}
private AnalogListener anlistener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
Vector3f direction = cam.getDirection().normalize().mult(5*tpf);
Vector3f left = cam.getLeft().normalize().mult(0.1f);
if (name.equals("forward")) {
move(direction);
} else if (name.equals("back")) {
move(direction.negate());
} else if (name.equals("left")) {
move(left);
} else if (name.equals("right")) {
move(left.negate());
}
}
};
private void move(Vector3f moveDir) {
Transform startPos = new Transform(playerNode.getLocalTranslation());
Transform endPos = new Transform(playerNode.getLocalTranslation().add(moveDir));
List<PhysicsSweepTestResult> sweep = bulletAppState.getPhysicsSpace().sweepTest(playerShape, startPos, endPos);
if (sweep.isEmpty()) {
playerNode.move(moveDir);
}
}
@Override
public void simpleUpdate(float tpf) {
cam.setLocation(playerNode.getWorldTranslation());
}
@Override
public void simpleRender(RenderManager rm) {
//TODO: add render code
}
}
[/java]
In this testcase, you can fly around and will be blocked, if the sweeptest returns a result that is not empty. It works fine for the smaller objects - but the sweeptest will miss the floor under certain angles and you can move through it.
I tested it with different collisionshapes and sizes for the sweeptest but this behaviour stays the same, as long as the collisionshape is small enough to fit through a single triangle of the collisionmesh.
Can anyone help me out?
Thanks, alfred
The sweep is probably too short.
I edited the testcase so that the sweeptest has to be at least 0.5 long:
[java]package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.PhysicsSweepTestResult;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.system.AppSettings;
import java.util.List;
public class Main extends SimpleApplication {
private BulletAppState bulletAppState;
public static void main(String[] args) {
Main app = new Main();
AppSettings settings = new AppSettings(true);
settings.setFrameRate(80);
app.start();
}
private CapsuleCollisionShape playerShape;
private Node playerNode;
@Override
public void simpleInitApp() {
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
Node geoNode = new Node(“geometries”);
rootNode.attachChild(geoNode);
Box b = new Box(new Vector3f(-5f, 0, 0), 1, 1, 1);
Geometry geom = new Geometry(“Box1”, b);
Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
mat.setColor(“Color”, ColorRGBA.Blue);
geom.setMaterial(mat);
geoNode.attachChild(geom);
Box b2 = new Box(Vector3f.ZERO.add(6f, 0, 0), 1, 3, 1);
Geometry geom2 = new Geometry(“Box2”, b2);
Material mat2 = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
mat2.setColor(“Color”, ColorRGBA.Red);
geom2.setMaterial(mat2);
geoNode.attachChild(geom2);
Box floor = new Box(new Vector3f(0, -3f, 0), 64f, 0.5f, 64f);
Geometry floorGeo = new Geometry(“Floor”, floor);
Material floorMat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
floorMat.setColor(“Color”, ColorRGBA.Green);
floorGeo.setMaterial(floorMat);
geoNode.attachChild(floorGeo);
Sphere s = new Sphere(5, 5, 1);
Geometry sGeo = new Geometry(“Sphere”, s);
sGeo.setLocalTranslation(1f, 0f, 3f);
Material sMat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
sMat.setColor(“Color”, ColorRGBA.Orange);
sGeo.setMaterial(sMat);
geoNode.attachChild(sGeo);
RigidBodyControl coll = new RigidBodyControl(0.0f);
geoNode.addControl(coll);
bulletAppState.getPhysicsSpace().add(coll);
playerNode = new Node(“Player”);
playerShape = new CapsuleCollisionShape(1.2f, 3f);
GhostControl playerGhost = new GhostControl(playerShape);
playerNode.addControl(playerGhost);
rootNode.attachChild(playerNode);
flyCam.setMoveSpeed(0.0f);
inputManager.addMapping(“forward”, new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping(“back”, new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping(“left”, new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping(“right”, new KeyTrigger(KeyInput.KEY_D));
inputManager.addListener(anlistener, “forward”, “back”, “left”, “right”);
}
private AnalogListener anlistener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
Vector3f direction = cam.getDirection().normalize().mult(50*tpf);
Vector3f left = cam.getLeft().normalize().mult(0.1f);
if (name.equals(“forward”)) {
move(direction);
} else if (name.equals(“back”)) {
move(direction.negate());
} else if (name.equals(“left”)) {
move(left);
} else if (name.equals(“right”)) {
move(left.negate());
}
}
};
private void move(Vector3f moveDir) {
Transform startPos = new Transform(playerNode.getLocalTranslation());
Transform endPos = new Transform(playerNode.getLocalTranslation().add(moveDir));
if (moveDir.length() < 0.5f) {
return;
}
List<PhysicsSweepTestResult> sweep = bulletAppState.getPhysicsSpace().sweepTest(playerShape, startPos, endPos);
if (sweep.isEmpty()) {
playerNode.move(moveDir);
}
}
@Override
public void simpleUpdate(float tpf) {
cam.setLocation(playerNode.getWorldTranslation());
}
@Override
public void simpleRender(RenderManager rm) {
//TODO: add render code
}
}
[/java]
While the tunneling has disappeared under big angles, you can still move through the floor if you hit it under small, almost horizontal angles:
http://imgur.com/znJPE
Well then theres nothing we can do. Does this happen in native bullet too?