First of all I’d like to say hello to this community, this is my first post. I recently installed JMonkeyEngine and have been doing the tutorials and having lots of fun with it. However, I came up to a problem that I can’t seem to fix
I reached the HelloPhysics tutorial but I have been incorporating all the tutorials into one project, not separately like the tutorial does.
My problem is that my cannonball is not shooting straight out into the direction the camera is facing. Seems to be a random direction or something.
When I copy and paste the tutorial code into its own project it works fine, but when it’s incorporated into my project (the one that also includes everything I’ve done in the other tutorials) it doesn’t work correctly (I have modified it to fit my code as best as I think I could).
I wasn’t sure which part of the code is the problem so I just posted the whole thing. Any help is appreciated.
[java]public class HelloJME3 extends SimpleApplication implements AnimEventListener{
public static void main(String[] args){
HelloJME3 app = new HelloJME3();
app.start();
}
private AnimChannel channel;
private AnimControl control;
Node player;
Node shootables;
Geometry mark;
protected Spatial ninja;
protected Geometry box;
protected Geometry shiny_rock;
private float x;
private float y;
private float z;
boolean isRunning = true;
private Material mat1;
private CollisionResult closest;
private Geometry g;
private BulletAppState bulletAppState;
private RigidBodyControl landscape;
private CharacterControl player1;
private Vector3f walkDirection = new Vector3f();
private CollisionResults results;
private boolean left = false,
right = false,
up = false,
down = false;
Material wall_mat;
Material stone_mat;
Material floor_mat;
private RigidBodyControl brick_phy;
private static final Box box1;
private RigidBodyControl ball_phy;
private static final Sphere sphere;
private RigidBodyControl floor_phy;
private static final Box floor;
private static final float brickLength = 0.48f;
private static final float brickWidth = 0.24f;
private static final float brickHeight = 0.12f;
static {
/** Initialize the cannon ball geometry */
sphere = new Sphere(32, 32, 0.4f, true, false);
sphere.setTextureMode(TextureMode.Projected);
/** Initialize the brick geometry */
box1 = new Box(Vector3f.ZERO, brickLength, brickHeight, brickWidth);
box1.scaleTextureCoordinates(new Vector2f(1f, .5f));
/** Initialize the floor geometry */
floor = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
floor.scaleTextureCoordinates(new Vector2f(3, 6));
}
@Override
public void simpleInitApp(){
/** Set up Physics */
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
flyCam.setMoveSpeed(100);
viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
initKeys();
initCrossHairs();
initMark();
setUpLight();
initMaterials();
initWall();
//add Town
Spatial town = assetManager.loadModel("Scenes/Town/main.j3o");
town.setLocalTranslation(0, -5.2f, 0);
town.setLocalScale(2);
rootNode.attachChild(town);
// We set up collision detection for the player by creating
// a capsule collision shape and a CharacterControl.
// The CharacterControl offers extra settings for
// size, stepheight, jumping, falling, and gravity.
// We also put the player in its starting position.
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 10f, 1);
player1 = new CharacterControl(capsuleShape, 0.05f);
player1.setJumpSpeed(20);
player1.setFallSpeed(30);
player1.setGravity(50);
player1.setPhysicsLocation(new Vector3f(0, 5, 5));
//Load controlable model
player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
player.setLocalScale(0.5f);
player.move(-10, 0, -10);
rootNode.attachChild(player);
control = player.getControl(AnimControl.class);
control.addListener(this);
channel = control.createChannel();
channel.setAnim("stand");
/** A simple textured cube -- in good MIP map quality. */
Box boxshape1 = new Box(new Vector3f(-3f,1.1f,0f), 1f,1f,1f);
Geometry cube = new Geometry("My Textured Box", boxshape1);
Material mat_stl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex_ml = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
mat_stl.setTexture("ColorMap", tex_ml);
cube.setMaterial(mat_stl);
cube.move(-10, 0, 0);
rootNode.attachChild(cube);
/** A translucent/transparent texture, similar to a window frame. */
Box boxshape3 = new Box(new Vector3f(0f,0f,0f), 1f,1f,0.01f);
Geometry window_frame = new Geometry("window frame", boxshape3);
Material mat_tt = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_tt.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tt.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
window_frame.setMaterial(mat_tt);
//Objects with transparency need to be in the render bucket
window_frame.setQueueBucket(Bucket.Transparent);
window_frame.move(-10, 0, 0);
rootNode.attachChild(window_frame);
/** A cube with base color "leaking" through a partially transparent texture */
Box boxshape4 = new Box(new Vector3f(3f,-1f,0f), 1f,1f,1f);
Geometry cube_leak = new Geometry("Leak-through color cube", boxshape4);
Material mat_tl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_tl.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tl.setColor("Color", new ColorRGBA(1f,0f,1f, 1f)); // purple
cube_leak.setMaterial(mat_tl);
cube_leak.move(-10, 0, 0);
rootNode.attachChild(cube_leak);
/** A bumpy rock with a shiny light effect */
Sphere rock = new Sphere(32, 32, 2f);
shiny_rock = new Geometry("Shiny rock", rock);
rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
TangentBinormalGenerator.generate(rock); // for lighting effect
Material mat_lit = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
mat_lit.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"));
mat_lit.setTexture("NormalMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
mat_lit.setBoolean("UseMaterialColors",true);
mat_lit.setColor("Specular",ColorRGBA.White);
mat_lit.setColor("Diffuse",ColorRGBA.White);
mat_lit.setFloat("Shininess", 5f); // [1,128]
shiny_rock.setMaterial(mat_lit);
shiny_rock.move(10, 0, 0);
rootNode.attachChild(shiny_rock);
//Pulsating Box
Box c = new Box(1, 1, 1);
box = new Geometry("pulsating box", c);
mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.Red);
box.setMaterial(mat1);
box.move(15, 0, 10);
rootNode.attachChild(box);
//add Teapot
Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
Material mat_default = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
teapot.setMaterial(mat_default);
rootNode.attachChild(teapot);
// Create a wall with a simple texture from test_data
Box boxW = new Box(Vector3f.ZERO, 2.5f,2.5f,1.0f);
Spatial wall = new Geometry("Box", boxW );
Material mat_brick = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_brick.setTexture("ColorMap",
assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
wall.setMaterial(mat_brick);
wall.setLocalTranslation(2.0f,-2.5f,0.0f);
rootNode.attachChild(wall);
// Display a line of text with a default font
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText helloText = new BitmapText(guiFont, false);
helloText.setSize(guiFont.getCharSet().getRenderedSize());
helloText.setText("Hello World");
helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
guiNode.attachChild(helloText);
// Load a model from test_data (OgreXML + material + texture)
ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
ninja.scale(0.04f, 0.04f, 0.04f);
ninja.rotate(0.0f, -3.0f, 0.0f);
ninja.setLocalTranslation(0.0f, -5.0f, -2.0f);
rootNode.attachChild(ninja);
//Create four colored boxes and a floor to shoot at
shootables = new Node("Shootables");
rootNode.attachChild(shootables);
shootables.attachChild(makeCube("a Dragon", -55f, 0f, 0f));
shootables.attachChild(makeCube("a tin can", -40f, -2f, 15f));
shootables.attachChild(makeCube("the Sheriff", -50f, 1f, 10f));
shootables.attachChild(makeCube("the Deputy", -45f, 0f, 25f));
// We set up collision detection for the scene by creating a
// compound collision shape and a static RigidBodyControl with mass zero.
CollisionShape sceneShape =
CollisionShapeFactory.createMeshShape((Node) town);
BoxCollisionShape wallShape = new BoxCollisionShape(new Vector3f(2.5f, 2.5f, 1f));
landscape = new RigidBodyControl(sceneShape, 0);
RigidBodyControl wallPhysics = new RigidBodyControl(wallShape, 0);
town.addControl(landscape);
wall.addControl(wallPhysics);
bulletAppState.getPhysicsSpace().add(landscape);
bulletAppState.getPhysicsSpace().add(player1);
bulletAppState.getPhysicsSpace().add(wallPhysics);
}
private void setUpLight() {
// We add light so we see the scene
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
rootNode.addLight(dl);
}
/** A cube object for target practice */
protected Geometry makeCube(String name, float x, float y, float z) {
Box box = new Box(new Vector3f(x, y, z), 0.1f, 2, 1f);
Geometry cube = new Geometry(name, box);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.randomColor());
cube.setMaterial(mat1);
return cube;
}
/** A red ball that marks the last spot that was "hit" by the "shot". */
protected void initMark() {
Sphere sphere = new Sphere(30, 30, 0.2f);
mark = new Geometry("BOOM!", sphere);
Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mark_mat.setColor("Color", ColorRGBA.Red);
mark.setMaterial(mark_mat);
}
/** A centred plus sign to help the player aim. */
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.setLocalTranslation( // center
settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
guiNode.attachChild(ch);
}
@Override
public void simpleUpdate(float tpf){
Vector3f camDir = cam.getDirection().clone().multLocal(0.3f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.2f);
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()); }
player1.setWalkDirection(walkDirection);
cam.setLocation(player1.getPhysicsLocation());
z += tpf;
if (z < 5){
shiny_rock.rotate(2*tpf, 0, 0);
shiny_rock.move(0, 0, 3*tpf);
}
else if (z < 10){
shiny_rock.rotate(-2*tpf, 0, 0);
shiny_rock.move(0, 0, -3*tpf);
}
else
z = 0;
box.rotate(0, 4*tpf, 0);
x += tpf;
if (x < 2)
box.scale(1 + tpf * 0.4f);
else if (x < 4)
box.scale(1 - tpf * 0.4f);
else
x = 0;
y += tpf;
if (y > 1) {
mat1.setColor("Color", ColorRGBA.randomColor());
y= 0;
}
}
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
if (animName.equals("Walk")) {
channel.setAnim("stand", 0.50f);
channel.setLoopMode(LoopMode.DontLoop);
channel.setSpeed(1f);
}
}
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
// unused
}
private void initKeys(){
//map the keys to the desired name
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Back", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_U));
inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
// Add the names to the action listener.
inputManager.addListener(myListener, new String[]{"Pause", "Left", "Right",
"Walk", "Jump",
"Forward", "Back", "Shoot"});
}
private Listener myListener = new Listener();
private class Listener implements ActionListener, AnalogListener{
public void onAction(String name, boolean value, float tpf){
if (name.equals("Left")){
//isRunning = !isRunning;
left = value;
} else if (name.equals("Right")){
right = value;
} else if (name.equals("Forward")){
up = value;
} else if (name.equals("Back")){
down = value;
} else if (name.equals("Jump")){
player1.jump();
}
if (name.equals("Walk")){
channel.setAnim("Walk", 0.50f);
channel.setLoopMode(LoopMode.Loop);
}
if (name.equals("Shoot") && !value) {
makeCannonBall();
}
}
public void onAnalog(String name, float value, float tpf) {
}
}
/** Initialize the materials used in this scene. */
public void initMaterials() {
wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TextureKey key = new TextureKey("Textures/Terrain/BrickWall/BrickWall.jpg");
key.setGenerateMips(true);
Texture tex = assetManager.loadTexture(key);
wall_mat.setTexture("ColorMap", tex);
stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
TextureKey key2 = new TextureKey("Textures/Terrain/Rock/Rock.PNG");
key2.setGenerateMips(true);
Texture tex2 = assetManager.loadTexture(key2);
stone_mat.setTexture("ColorMap", tex2);
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);
}
/** This loop builds a wall out of individual bricks. */
public void initWall() {
float startpt = brickLength / 4;
float height = 0;
for (int j = 0; j < 15; j++) {
for (int i = 0; i < 6; i++) {
Vector3f vt =
new Vector3f(i * brickLength * 2 + startpt, brickHeight + height, 0);
makeBrick(vt);
}
startpt = -startpt;
height += 2 * brickHeight;
}
}
/** This method creates one individual physical brick. */
public void makeBrick(Vector3f loc) {
/** Create a brick geometry and attach to scene graph. */
Geometry brick_geo = new Geometry("brick", box1);
brick_geo.setMaterial(wall_mat);
rootNode.attachChild(brick_geo);
/** Position the brick geometry */
brick_geo.setLocalTranslation(loc);
/** Make brick physical with a mass > 0.0f. */
brick_phy = new RigidBodyControl(2f);
/** Add physical brick to physics space. */
brick_geo.addControl(brick_phy);
bulletAppState.getPhysicsSpace().add(brick_phy);
}
/** This method creates one individual physical cannon ball.
* By defaul, the ball is accelerated and flies
* from the camera position in the camera direction.*/
public void makeCannonBall() {
/** Create a cannon ball geometry and attach to scene graph. */
Geometry ball_geo = new Geometry("cannon ball", sphere);
ball_geo.setMaterial(stone_mat);
rootNode.attachChild(ball_geo);
/** Position the cannon ball */
ball_geo.setLocalTranslation(cam.getLocation());
/** Make the ball physcial 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);
/** Accelerate the physcial ball to shoot it. */
ball_phy.setLinearVelocity(cam.getDirection().mult(25));
}
} [/java]