Start position of projectile not updated with camera

Hi All,



I’m combining the hellophysics tutorial with the helloterraincollision tutorial to experiment with FPS.

The trouble is that the startposition and shooting direction is not updated with the player/camera position and direction. Can anyone help?

Here’s the code to try it out yourself:



package jme3test.helloworld;



import com.jme3.app.SimpleApplication;

import com.jme3.asset.TextureKey;

import com.jme3.audio.AudioNode;

import com.jme3.bullet.BulletAppState;

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.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.font.BitmapText;

import com.jme3.math.Vector3f;

import com.jme3.renderer.Camera;

import com.jme3.scene.Node;

import com.jme3.scene.shape.Sphere;

import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.terrain.heightmap.AbstractHeightMap;

import com.jme3.terrain.geomipmap.TerrainQuad;

import com.jme3.terrain.heightmap.ImageBasedHeightMap;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import java.util.ArrayList;

import java.util.List;

import jme3tools.converters.ImageToAwt;

import com.jme3.scene.shape.Sphere.TextureMode;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.input.MouseInput;

import com.jme3.scene.Geometry;

import java.util.logging.*;





/**

  • This demo shows a terrain with collision detection,
  • that you can walk around in with a first-person perspective.
  • This code combines HelloCollision and HelloTerrain.

    /

    public class ArtilleryGame extends SimpleApplication

    implements ActionListener {



    private BulletAppState bulletAppState;

    private RigidBodyControl landscape;

    private CharacterControl player;

    private Vector3f walkDirection = new Vector3f();

    private boolean left = false, right = false, up = false, down = false;

    private TerrainQuad terrain;

    private Material mat_terrain;

    private RigidBodyControl ball_phy;

    private static final Sphere sphere;

    private static final Logger logger = Logger.getLogger(ArtilleryGame.class.getName());



    /
    * Prepare Materials /

    Material stone_mat;

    // Prepare soundnodes

    private AudioNode audio_gun;

    private AudioNode audio_nature;





    static {

    /
    * Initialize the cannon ball geometry /

    sphere = new Sphere(32, 32, 0.4f, true, false);

    sphere.setTextureMode(TextureMode.Projected);

    }



    public static void main(String[] args) {

    logger.setLevel(Level.WARNING);

    logger.log(Level.WARNING, “Dit is een test”);

    ArtilleryGame app = new ArtilleryGame();

    app.start();

    }



    @Override

    public void simpleInitApp() {



    /
    * Set up Physics /

    bulletAppState = new BulletAppState();

    stateManager.attach(bulletAppState);

    //bulletAppState.getPhysicsSpace().enableDebug(assetManager);

    bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0f,-0.25f,0f));



    flyCam.setMoveSpeed(100);



    // /
    * Add InputManager action: Left click triggers shooting. /



    /
    * 1. Create terrain material and load four textures into it. /

    mat_terrain = new Material(assetManager,

    “Common/MatDefs/Terrain/Terrain.j3md”);



    /
    * 1.1) Add ALPHA map (for red-blue-green coded splat textures) /

    mat_terrain.setTexture(“Alpha”, assetManager.loadTexture(

    “Textures/Terrain/splat/alphamap.png”));



    /
    * 1.2) Add GRASS texture into the red layer (Tex1). /

    Texture grass = assetManager.loadTexture(

    “Textures/Terrain/splat/grass.jpg”);

    grass.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture(“Tex1”, grass);

    mat_terrain.setFloat(“Tex1Scale”, 64f);



    /
    * 1.3) Add DIRT texture into the green layer (Tex2) /

    Texture dirt = assetManager.loadTexture(

    “Textures/Terrain/splat/dirt.jpg”);

    dirt.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture(“Tex2”, dirt);

    mat_terrain.setFloat(“Tex2Scale”, 32f);



    /
    * 1.4) Add ROAD texture into the blue layer (Tex3) /

    Texture rock = assetManager.loadTexture(

    “Textures/Terrain/splat/road.jpg”);

    rock.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture(“Tex3”, rock);

    mat_terrain.setFloat(“Tex3Scale”, 128f);



    // Add stonematerial for cannonball

    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);



    /
    * 2. Create the height map /

    AbstractHeightMap heightmap = null;

    Texture heightMapImage = assetManager.loadTexture(

    “Textures/Terrain/splat/mountains512.png”);

    heightmap = new ImageBasedHeightMap(

    ImageToAwt.convert(heightMapImage.getImage(), false, true, 0));

    heightmap.load();



    /
    * 3. We have prepared material and heightmap.
  • Now we create the actual terrain:
  • 3.1) Create a TerrainQuad and name it “my terrain”.
  • 3.2) A good value for terrain tiles is 64x64 – so we supply 64+1=65.
  • 3.3) We prepared a heightmap of size 512x512 – so we supply 512+1=513.
  • 3.4) As LOD step scale we supply Vector3f(1,1,1).
  • 3.5) We supply the prepared heightmap itself.

    /

    terrain = new TerrainQuad(“my terrain”, 65, 513, heightmap.getHeightMap());



    /
    * 4. We give the terrain its material, position & scale it, and attach it. /

    terrain.setMaterial(mat_terrain);

    terrain.setLocalTranslation(0, -100, 0);

    terrain.setLocalScale(2f, 1f, 2f);

    rootNode.attachChild(terrain);



    /
    * 5. The LOD (level of detail) depends on were the camera is: /

    List cameras = new ArrayList();

    cameras.add(getCamera());

    TerrainLodControl control = new TerrainLodControl(terrain, cameras);

    terrain.addControl(control);



    /
    * 6. Add physics: /

    // We set up collision detection for the scene by creating a

    // compound collision shape and a static RigidBodyControl with mass zero.
    /

    CollisionShape terrainShape =

    CollisionShapeFactory.createMeshShape((Node) terrain);

    landscape = new RigidBodyControl(terrainShape, 0);

    terrain.addControl(landscape);



    // 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, 6f, 1);

    player = new CharacterControl(capsuleShape, 0.05f);

    player.setJumpSpeed(20);

    player.setFallSpeed(30);

    player.setGravity(30);

    player.setPhysicsLocation(new Vector3f(0, 10, 0));



    // We attach the scene and the player to the rootnode and the physics space,

    // to make them appear in the game world.

    bulletAppState.getPhysicsSpace().add(terrain);

    logger.log(Level.WARNING, “Player added”);

    bulletAppState.getPhysicsSpace().add(player);

    setUpKeys();

    initCrossHairs();

    initAudio();

    }



    /** We create two audio nodes. /

    private void initAudio() {

    /
    gun shot sound is to be triggered by a mouse click. /

    audio_gun = new AudioNode(assetManager, “Sound/Effects/Gun.wav”, false);

    audio_gun.setLooping(false);

    audio_gun.setVolume(2);

    rootNode.attachChild(audio_gun);



    /
    nature sound - keeps playing in a loop. /

    audio_nature = new AudioNode(assetManager, “Sound/Environment/Nature.ogg”, false);

    audio_nature.setLooping(true); // activate continuous playing

    audio_nature.setPositional(true);

    audio_nature.setLocalTranslation(Vector3f.ZERO.clone());

    audio_nature.setVolume(3);

    rootNode.attachChild(audio_nature);

    audio_nature.play(); // play continuously!

    }





    /
    * 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_A));

    inputManager.addMapping(“Right”, new KeyTrigger(KeyInput.KEY_D));

    inputManager.addMapping(“Up”, new KeyTrigger(KeyInput.KEY_W));

    inputManager.addMapping(“Down”, new KeyTrigger(KeyInput.KEY_S));

    inputManager.addMapping(“Jump”, new KeyTrigger(KeyInput.KEY_SPACE));

    inputManager.addMapping(“leftclick”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));

    inputManager.addListener(this, “Left”);

    inputManager.addListener(this, “Right”);

    inputManager.addListener(this, “Up”);

    inputManager.addListener(this, “Down”);

    inputManager.addListener(this, “Jump”);

    inputManager.addListener(actionListener, “leftclick”);

    }



    /
    * Defining the “Shoot” action: Play a gun sound. /

    private ActionListener actionListener = new ActionListener() {

    @Override

    public void onAction(String name, boolean keyPressed, float tpf) {

    if (name.equals(“leftclick”) && !keyPressed) {

    logger.log(Level.WARNING,“LOG: Cannon fired”);

    audio_gun.playInstance(); // play each instance once!

    makeCannonBall();

    }

    }

    };



    /
    * 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(“Up”)) {

    if (value) { up = true; } else { up = false; }

    } else if (binding.equals(“Down”)) {

    if (value) { down = true; } else { down = false; }

    } else if (binding.equals(“Jump”)) {

    player.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 (up) { walkDirection.addLocal(camDir); }

    if (down) { walkDirection.addLocal(camDir.negate()); }

    player.setWalkDirection(walkDirection);

    cam.setLocation(player.getPhysicsLocation());

    }







    /
    * 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());

    ball_geo.setLocalTranslation(player.getPhysicsLocation());

    // ball_geo.setLocalTranslation(player.getWalkDirection().multLocal(-2f));



    /
    * 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 physical ball to shoot it. /

    //ball_phy.setLinearVelocity(cam.getDirection().mult(25));

    ball_phy.setLinearVelocity(player.getViewDirection().mult(25));

    }



    /
    * A plus sign used as crosshairs to help the player with aiming.
    /

    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("+"); // fake crosshairs :slight_smile:

    ch.setLocalTranslation( // center

    settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,

    settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);

    guiNode.attachChild(ch);

    }

    }

Your problem is that you set the postition of the ball_geo to the player.physicsLocation witch is ( i think ) erverytime the same…





Use

[java]ball_geo.setLocalTranslation(cam.getLocalTranslation);[/java]