Hello fellow coders,
I’ve tried to integrate the raycollision example in the hellocollision example (with the town.zip level) and everything seems to work fine, except for the returned ContactPoint of the (nearest) collision. This one is way of course, so I’m wondering if there’s a bug in place or that I’m making a newbmistake.
Any help is very much appreciated!
[java]package mygame;
import com.fluendo.utils.Debug;
import com.jme3.app.SimpleBulletApplication;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
import com.jme3.bullet.nodes.PhysicsCharacterNode;
import com.jme3.bullet.nodes.PhysicsNode;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
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.Ray;
import com.jme3.math.Vector3f;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.shadow.BasicShadowRenderer;
/**
- Example 9 - How to make walls and floors solid.
- This version uses Physics and a custom Action Listener.
-
@author normen, with edits by Zathras
/
public class Main
extends SimpleBulletApplication
implements ActionListener {
Geometry mark;
PhysicsNode levelNode;
private Spatial gameScene;
private PhysicsCharacterNode player;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, up = false, down = false;
public static void main(String[] args) {
Main app = new Main();
app.showSettings=false;
app.start();
}
void addViewportAttributes(ViewPort view) {
BasicShadowRenderer bsr = new BasicShadowRenderer(assetManager, 1024);
bsr.setDirection(new Vector3f(-2.8f, -2.8f, -2.8f).normalize());
view.addProcessor(bsr);
}
public void simpleInitApp() {
renderer.setBackgroundColor(ColorRGBA.Cyan);
// We re-use the flyby camera for rotation, while positioning is handled by physics
flyCam.setMoveSpeed(100);
setupKeys();
addViewportAttributes(viewPort);
// We add a light so we see the scene
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White.clone().multLocal(2));
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalize());
rootNode.addLight(dl);
// We load the scene from the zip file and adjust its size.
assetManager.registerLocator(“town.zip”, ZipLocator.class.getName());
gameScene = assetManager.loadModel(“main.scene”);
gameScene.setLocalScale(2f);
initMark();
initCrossHairs();
// We set up collision detection by creating a
// compound collision shape and a physics node for the scene.
CompoundCollisionShape sceneShape = CollisionShapeFactory.createMeshCompoundShape((Node) gameScene);
levelNode = new PhysicsNode(gameScene, sceneShape, 0);
levelNode.setShadowMode(ShadowMode.CastAndRecieve);
// Here we set up collision detection for the player by creating
// a capsule collision shape and a physics character node.
// The physics character node offers extra settings for
// size, stepheight, jumping, falling, and gravity.
// We also put the player in its starting position.
player = new PhysicsCharacterNode(new CapsuleCollisionShape(1.5f, 6f, 1), .05f);
player.setJumpSpeed(20);
player.setFallSpeed(30);
player.setGravity(30);
player.setLocalTranslation(new Vector3f(0, 10, 0));
player.updateGeometricState();
// We attach the scene and the player to the rootnode and the physics space,
// to make them appear in the game world.
rootNode.attachChild(levelNode);
rootNode.attachChild(player);
rootNode.updateGeometricState();
getPhysicsSpace().add(levelNode);
getPhysicsSpace().add(player);
}
/* We over-write some navigational key mappings here, so we can
- add physics-controlled walking and jumping: /
private void setupKeys() {
inputManager.addMapping(“Lefts”, new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping(“Rights”, new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping(“Ups”, new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping(“Downs”, new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping(“Jumps”, new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(this, “Lefts”);
inputManager.addListener(this, “Rights”);
inputManager.addListener(this, “Ups”);
inputManager.addListener(this, “Downs”);
inputManager.addListener(this, “Jumps”);
inputManager.addMapping(“Shoot”,
new KeyTrigger(KeyInput.KEY_LCONTROL), // trigger 1: spacebar
new MouseButtonTrigger(0)); // trigger 2: left-button click
inputManager.addListener(this, “Shoot”);
}
/* A red ball that marks the last spot that was “hit” by the “shot”. /
protected void initMark() {
Sphere sphere = new Sphere(30, 30, 2f);
mark = new Geometry(“BOOM!”, sphere);
Material mark_mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);
mark_mat.setColor(“m_Color”, ColorRGBA.Red);
mark.setMaterial(mark_mat);
}
/* 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(“Lefts”)) {
if (value) { left = true; } else { left = false; }
} else if (binding.equals(“Rights”)) {
if (value) { right = true; } else { right = false; }
} else if (binding.equals(“Ups”)) {
if (value) { up = true; } else { up = false; }
} else if (binding.equals(“Downs”)) {
if (value) { down = true; } else { down = false; }
} else if (binding.equals(“Jumps”)) {
player.jump();
}else if (binding.equals(“Shoot”) && !value) {
// 1. Reset results list.
CollisionResults results = new CollisionResults();
// 2. Aim the ray from cam loc to cam direction.
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// 3. Collect intersections between Ray and Shootables in results list.
levelNode.collideWith(ray, results);
// 4. Print the results
System.out.println("
Collisions? " + results.size() + "
");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of geometry.
float dist = results.getCollision(i).getDistance();
Vector3f pt = results.getCollision(i).getContactPoint();
// String hit = results.getCollision(i).getGeometry().getName();
System.out.println("* Collision #" + i + " at " + pt.toString());
//System.out.println(" You shot " + hit + " at " + pt + ", " + dist + " wu away.");
}
// 5. Use the results (we mark the hit object)
if (results.size() > 0){
// The closest collision point is what was truly hit:
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
mark.setLocalTranslation(closest.getContactPoint());
Debug.warn(closest.getContactPoint().toString());
rootNode.attachChild(mark);
} else {
// No hits? Then remove the red mark.
rootNode.detachChild(mark);
}
}
}
/**
* 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 (up) { walkDirection.addLocal(camDir); }
if (down) { walkDirection.addLocal(camDir.negate()); }
player.setWalkDirection(walkDirection);
cam.setLocation(player.getLocalTranslation());
}
protected void initCrossHairs() {
guiNode.detachAllChildren();
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
ch.setText("+"); // crosshairs
ch.setColor(ColorRGBA.White);
ch.setLocalTranslation( // center
settings.getWidth()/2 - guiFont.getCharSet().getRenderedSize()/3*2,
settings.getHeight()/2 + ch.getLineHeight()/2, 0);
guiNode.attachChild(ch);
}
}
[/java]