Problem rotating object with FPS camera

I am working on this piece of code where i want to make to make FPS like game And i want the gun to be always visible in front of me even when i rotate the camera !

I have a playerNode which is the player ! So i attached the gun to the PlayerNode ,
So that gun would move along with the playerNode !
But it’s not working (The gun is not moving with the playerNode and is not visible)
What am i doing wrong ?

(I just want the gun to be in front of the camera all the time like a FPS game even
when i rotate the flycam )

here’s my code …
Please check it and correct me where i am doing wrong !

[java]
package mygame;

import com.jme3.app.SimpleApplication;
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.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.FogFilter;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**

  • Example 9 - How to make walls and floors solid.

  • This collision code uses Physics and a custom Action Listener.

  • @author normen, with edits by Zathras
    */
    public class FirstPerson1 extends SimpleApplication
    implements ActionListener {

    private BitmapText ch;
    private TerrainQuad terrain;
    Geometry mark;
    Material mat_terrain;

private AudioNode audio_gun,audio_nature;
private Node playerNode;
private Spatial sceneModel;
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 boolean isTargeting=false;

Spatial gun;

public static void main(String[] args) {
FirstPerson1 app = new FirstPerson1();
app.start();
}

public void simpleInitApp() {
/** Set up Physics */
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);

viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));

flyCam.setMoveSpeed(100f);
flyCam.setRotationSpeed(10f);
flyCam.setEnabled(true);


loadAudio();
initMark();
loadTerrain();
loadEffects();
setUpKeys();
setUpLight();

// 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((Spatial)terrain);
landscape = new RigidBodyControl(sceneShape, 0);
terrain.addControl(landscape);


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, 50, 0));

playerNode=new Node("Player Node");
playerNode.setLocalTranslation(player.getPhysicsLocation());
playerNode.addControl(player);


  gun = assetManager.loadModel("Models/pistol.j3o");
  gun.setName("gun");
  gun.scale(0.5f);
  gun.move(0, 0, -5); // move it to front to make it visible
  playerNode.attachChild(gun);
    

rootNode.attachChild(terrain);
rootNode.attachChild(playerNode);

// rootNode.attachChild(gun);

bulletAppState.getPhysicsSpace().add(landscape);
bulletAppState.getPhysicsSpace().add(player);

}

private void loadAudio()
{
/* 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(false);
audio_nature.setLocalTranslation(Vector3f.ZERO.clone());
audio_nature.setVolume(3);
rootNode.attachChild(audio_nature);
audio_nature.play(); // play continuously!

}

private void loadTerrain()
{
/** 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);

/** 2. Create the height map */
AbstractHeightMap heightmap = null;
Texture heightMapImage = assetManager.loadTexture(
        "Textures/Terrain/splat/mountains512.png");
heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
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.
 */
int patchSize = 65;
terrain = new TerrainQuad("my terrain", patchSize, 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: */
TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
terrain.addControl(control);

}

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

}

/** 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("Forward", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("Target", new KeyTrigger(KeyInput.KEY_LCONTROL));
inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));


inputManager.addListener(this, "Left");
inputManager.addListener(this, "Right");
inputManager.addListener(this, "Forward");
inputManager.addListener(this, "Backward");
inputManager.addListener(this, "Jump");
inputManager.addListener(this, "Target");
inputManager.addListener(this, "Shoot");

}

protected void initCrossHairs() {

 guiNode.detachAllChildren();
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
ch.setText("+");        // fake crosshairs :)

ch.setLocalTranslation( // center
  settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
  settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);

guiNode.attachChild(ch);

}

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

}

/** 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”)) {
    left = value;
    } else if (binding.equals(“Right”)) {
    right = value;
    } else if (binding.equals(“Forward”)) {
    up = value;
    } else if (binding.equals(“Backward”)) {
    down = value;
    } else if (binding.equals(“Jump”)) {
    player.jump();
    }else if (binding.equals(“Target”)) {
    isTargeting=value;

    if(isTargeting)initCrossHairs();
    else guiNode.detachAllChildren();

}

if(isTargeting && binding.equals("Shoot") && !value)
{
    Shoot();
}

}

private void Shoot()
{

    audio_gun.playInstance();
    
    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.
    
    
    terrain.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);
      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());
      rootNode.attachChild(mark);
    } else {
      // No hits? Then remove the red mark.
      rootNode.detachChild(mark);
    }

}

@Override
public void simpleUpdate(float tpf) {

Vector3f camDir = cam.getDirection().clone().multLocal(0.4f);
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);
player.setViewDirection(cam.getDirection());

cam.setLocation(player.getPhysicsLocation());

listener.setLocation(cam.getLocation());
listener.setRotation(cam.getRotation());

Debug();

}

private void Debug()
{
  System.out.println("Player Postion: "+playerNode.getLocalTranslation());
  System.out.println("Player Rotation: "+playerNode.getLocalRotation());
 
  System.out.println("Gun position: "+playerNode.getChild("gun").getLocalTranslation());
  System.out.println("Gun rotation: "+playerNode.getChild("gun").getLocalRotation());
}

private void loadEffects() {
    
     /** Add fog to a scene */
    FilterPostProcessor fpp=new FilterPostProcessor(assetManager);
    FogFilter fog=new FogFilter();
    fog.setFogColor(new ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f));
    fog.setFogDistance(155);
    fog.setFogDensity(1.2f);
    fpp.addFilter(fog);
    viewPort.addProcessor(fpp);

    
}

}

[/java]

i 've also tried

[java]

gun.setLocalTranslation(cam.getLocation().add(0,0,-5));
gun.setLocalRotation(cam.getRotation());

[/java]

in the simpleUpdate but it doesn’t move with flycam !

Just set the playerNode to the same location as the camera in the update loop

Also, where you have gun.move(0,0,-5), what made you choose -5 z axis? Play around with those 3 values.

And finally, once your camera is behind your gun you might experience more problems. It will appear your gun is chopped in half as your model will be partly behind your view frustum (I think that is the correct terminology).

EDIT: Take your player off the player node and add it to the rootNode instead too

How do you know it isn’t moving with the player if it’s not visible?

Since the default near clipping plane is at 1 meter then you probably won’t see a gun that is less than one meter away from the camera.

@Dan: PlayerNode

@javagame said: Just set the playerNode to the same location as the camera in the update loop

Also, where you have gun.move(0,0,-5), what made you choose -5 z axis? Play around with those 3 values.

And finally, once your camera is behind your gun you might experience more problems. It will appear your gun is chopped in half as your model will be partly behind your view frustum (I think that is the correct terminology).

EDIT: Take your player off the player node and add it to the rootNode instead too

The playerNode is always at the same pos as the camera
Cause playerNode is controlled by player (CharacterControl)
and i set cam.setLocation(player.getPhysicsLocation())

@pspeed said: How do you know it isn't moving with the player if it's not visible?

Since the default near clipping plane is at 1 meter then you probably won’t see a gun that is less than one meter away from the camera.

That’s why moved the gun 5 world units in front of the camera, so that it would be visible !
Since gun is attached to the playerNode shouldn’t the gun move and rotate with the playerNode ?
I can see the playerNode is moving but the attached gun is not by printing out their position !

Oh I see. Maybe your gun is behind your camera then like pspeed said?

Made a few changes now i can see the gun But it does not move with flyCam !
How to make it move with the flycam ? (how to put it in the same screen position even when i 'm rotating the cam)
Please let me know if can fix the code !
And here’s the gun model http://opengameart.org/content/textured-pistol

[java]

package mygame;

import com.bulletphysics.collision.shapes.QuantizedBvhNodes;
import com.jme3.app.SimpleApplication;
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.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.FogFilter;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

/**

  • Example 9 - How to make walls and floors solid.

  • This collision code uses Physics and a custom Action Listener.

  • @author normen, with edits by Zathras
    */
    public class FirstPerson1 extends SimpleApplication
    implements ActionListener {

    private BitmapText ch;
    private TerrainQuad terrain;
    Geometry mark;
    Material mat_terrain;

private AudioNode audio_gun,audio_nature;
private Node playerNode;
private Spatial sceneModel;
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 boolean isTargeting=false;

Spatial gun;

public static void main(String[] args) {
FirstPerson1 app = new FirstPerson1();
app.start();
}

public void simpleInitApp() {
/** Set up Physics */
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);

viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));

flyCam.setMoveSpeed(100f);
flyCam.setRotationSpeed(10f);
flyCam.setEnabled(true);


loadAudio();
initMark();
loadTerrain();
loadEffects();
setUpKeys();
setUpLight();

// 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((Spatial)terrain);
landscape = new RigidBodyControl(sceneShape, 0);
terrain.addControl(landscape);


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, 50, 0));

playerNode=new Node("Player Node");
playerNode.setLocalTranslation(player.getPhysicsLocation());
playerNode.addControl(player);

gun = assetManager.loadModel("Models/pistol.j3o");
gun.scale(0.1f);


rootNode.attachChild(terrain);
rootNode.attachChild(playerNode);
rootNode.attachChild(gun);

bulletAppState.getPhysicsSpace().add(landscape);
bulletAppState.getPhysicsSpace().add(player);

}

private void loadAudio()
{
/* 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(false);
audio_nature.setLocalTranslation(Vector3f.ZERO.clone());
audio_nature.setVolume(3);
rootNode.attachChild(audio_nature);
audio_nature.play(); // play continuously!

}

private void loadTerrain()
{
/** 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);

/** 2. Create the height map */
AbstractHeightMap heightmap = null;
Texture heightMapImage = assetManager.loadTexture(
        "Textures/Terrain/splat/mountains512.png");
heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
heightmap.load();


int patchSize = 65;
terrain = new TerrainQuad("my terrain", patchSize, 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: */
TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
terrain.addControl(control);

}

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

}

/** 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("Forward", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("Target", new KeyTrigger(KeyInput.KEY_LCONTROL));
inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));


inputManager.addListener(this, "Left");
inputManager.addListener(this, "Right");
inputManager.addListener(this, "Forward");
inputManager.addListener(this, "Backward");
inputManager.addListener(this, "Jump");
inputManager.addListener(this, "Target");
inputManager.addListener(this, "Shoot");

}

protected void initCrossHairs() {

 guiNode.detachAllChildren();
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
ch = new BitmapText(guiFont, false);
ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
ch.setText("+");        // fake crosshairs :)

ch.setLocalTranslation( // center
  settings.getWidth() / 2 - guiFont.getCharSet().getRenderedSize() / 3 * 2,
  settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);

guiNode.attachChild(ch);

}

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

}

/** 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”)) {
    left = value;
    } else if (binding.equals(“Right”)) {
    right = value;
    } else if (binding.equals(“Forward”)) {
    up = value;
    } else if (binding.equals(“Backward”)) {
    down = value;
    } else if (binding.equals(“Jump”)) {
    player.jump();
    }else if (binding.equals(“Target”)) {
    isTargeting=value;

    if(isTargeting)initCrossHairs();
    else guiNode.detachAllChildren();

}

if(isTargeting && binding.equals("Shoot") && !value)
{
    Shoot();
}

}

private void Shoot()
{

    audio_gun.playInstance();
    
    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.
    
    
    terrain.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);
      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());
      rootNode.attachChild(mark);
    } else {
      // No hits? Then remove the red mark.
      rootNode.detachChild(mark);
    }

}

@Override
public void simpleUpdate(float tpf) {

Vector3f camDir = cam.getDirection().clone().multLocal(0.4f);
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);
player.setViewDirection(cam.getDirection());


cam.setLocation(player.getPhysicsLocation());

 
 gun.setLocalTranslation(cam.getLocation().addLocal(0, 0, -2));
// gun.setLocalRotation(new Quaternion().fromAngles(FastMath.DEG_TO_RAD*90, -FastMath.DEG_TO_RAD*70, -FastMath.DEG_TO_RAD*45));
  gun.setLocalRotation(cam.getRotation());

listener.setLocation(cam.getLocation());
listener.setRotation(cam.getRotation());

Debug();

}

private void Debug()
{
  System.out.println("Player Postion: "+playerNode.getLocalTranslation());
  System.out.println("Player Rotation: "+playerNode.getLocalRotation());
 
  System.out.println("Gun position: "+gun.getLocalTranslation());
  System.out.println("Gun rotation: "+gun.getLocalRotation());
}

private void loadEffects() {
    
     /** Add fog to a scene */
    FilterPostProcessor fpp=new FilterPostProcessor(assetManager);
    FogFilter fog=new FogFilter();
    fog.setFogColor(new ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f));
    fog.setFogDistance(155);
    fog.setFogDensity(1.2f);
    fpp.addFilter(fog);
    viewPort.addProcessor(fpp);

    
}

}

[/java]