Fix gun in right bottom corner

hello I’m developing a first person shooter ,I read many similar post but after many attempts.I don’t be able to fix the gun (like first person shooter). I like flycam with “wasd” movement and mouse rotation but in two day I can’t able to fix the gun(it is behind) in the right angle bottom for every movement and rotation of player :frowning: please help me
this is the test code:

[java]

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
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.font.BitmapText;
import com.jme3.input.ChaseCamera;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.control.CameraControl.ControlDirection;
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;
import com.jogamp.opengl.math.geom.Frustum.Location;

public class Main extends SimpleApplication implements ActionListener,AnimEventListener{
private ChaseCamera cn;
private AnimChannel channel;
private AnimControl control;
private Node sword;
private CharacterControl player;
private Node playerNode;
private RigidBodyControl landscape;
private BulletAppState bulletAppState;
//Temporary vectors used on each frame.
//They here to avoid instanciating new vectors on each frame
private Vector3f camDir = new Vector3f();
private Vector3f camLeft = new Vector3f();
private Vector3f camPosition;
private TerrainQuad terrain;
private Material mat_terrain;
private boolean left = false, right = false, up = false, down = false;
private Vector3f walkDirection = new Vector3f();
public static void main(String[] args) {
Main app = new Main();
app.start();
}
private void initTerrain()
{
/** 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/road_normal.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);

	CollisionShape sceneShape =
			CollisionShapeFactory.createMeshShape((Node) terrain);
	landscape = new RigidBodyControl(sceneShape, 0);
	terrain.addControl(landscape);
	bulletAppState.getPhysicsSpace().add(terrain);
}

private void initPlayer(){
	flyCam.setMoveSpeed(100);
	flyCam.setEnabled(true);
	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, 100, 0));
	bulletAppState.getPhysicsSpace().add(player);
	
	sword =  (Node) assetManager.loadModel("assets/saiga.blend");
	sword.setLocalScale(0.5f, 0.5f, 0.5f);
	sword.rotate(0,0,0);
	sword.move(0, -1, 5);
	   //add all at node
	playerNode = new Node("player node");
	playerNode.addControl(player);
	player.setPhysicsLocation(new Vector3f(0, 100, 0));
    //my object in a node
	playerNode.attachChild(sword);
	
	rootNode.attachChild(playerNode);
}

@Override
public void simpleInitApp(){
	/** Set up Physics */
	bulletAppState = new BulletAppState();
	stateManager.attach(bulletAppState);
	//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
	viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));

	AmbientLight al = new AmbientLight();
	al.setColor(ColorRGBA.White.mult(1.3f));
	rootNode.addLight(al);

	setUpKeys();
	initTerrain();
	initPlayer();
	initCrossHairs();
}

public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName){
	if (animName.equals("sword swing")) {
		channel.setAnim("sword idle", 0.50f);
		channel.setLoopMode(LoopMode.Loop);
		channel.setSpeed(1f);
	}
}

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("ATTACK", 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(this, "ATTACK");
}

public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
	// unused
}
Vector3f location;

@Override
public void simpleUpdate(float tpf) {
	camDir.set(cam.getDirection()).multLocal(0.6f);
	camLeft.set(cam.getLeft()).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());
                      		    
}

protected void initCrossHairs() {
	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 simpleRender(RenderManager rm) {
	//TODO: add render code
}

public void onAction(String name, boolean isPressed, float tpf) {
	if (isPressed)
	{
		if (name.equals("ATTACK"))
		{
			channel.setAnim("sword swing");
			channel.setLoopMode(LoopMode.DontLoop);
		}
	}
	if (name.equals("Left")) {
		left = isPressed;
	} else if (name.equals("Right")) {
		right= isPressed;
	} else if (name.equals("Up")) {
		up = isPressed;
	} else if (name.equals("Down")) {
		down = isPressed;
	} else if (name.equals("Jump")) {
		if (isPressed) { player.jump(); }
	}
}

}
[/java]

this is because the sword is attached to the player, not to the camera.

What i like to do is use a cameranode and attach to this node a sub node which has the weapon.

Btw, you are setting an offset of y=-1 and z=5, which means 1 meter below the player (not the camera !) and 5 meter in front of him. He has very looong arms :slight_smile:
This is why you have your sword under the player.

Also remember that in many fps, they tweak the weapon display, cause what we see on screen is not what we see in realy life (cause of fov difference, mainly).

You can see this in dead island for exemple http://www.youtube.com/watch?v=hXmZX8iz2SE
So, even if your weapon is irl at ~y=30cm & z=35 (from HEAD, so you must add to this the player height) you cannot use that directly ingame or the weapon will appear far.

End, for the last point, you should consider the option to render the weapon after everything else, otherwise the weapon will possibly go through wall when you are too close to them.

thanks too much for the reply:) ,howewer I’m learning and now I’m a beginner and my english understanding is chip ,so I can consider a tip at a time:
I report you just one modification and just one doubt a time :

for follow this: “use a cameranode and attach to this node a sub node which has the weapon” i do this modification:

[java]
private void initPlayer(){
flyCam.setMoveSpeed(100);
flyCam.setEnabled(true);
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, 100, 0));
bulletAppState.getPhysicsSpace().add(player);

	sword =  (Node) assetManager.loadModel("assets/saiga.blend");
	sword.setLocalScale(0.5f, 0.5f, 0.5f);
   
		//   PLAYER NODE WITH THE WEAPON
	playerNode = new Node("player node");
	playerNode.addControl(player);
	player.setPhysicsLocation(new Vector3f(0, 100, 0));
    playerNode.attachChild(sword);      
    
    
    //  MY MODIFICATION  IT'S OK?? 
    cameraNode_1= new CameraNode();
    //sub node with WEAPON  
	cameraNode_1.attachChild(playerNode);
	
	
	rootNode.attachChild(playerNode);
}

[/java]

the result is
: the gun is on my head while I walk.
question 1): it’s ok the modification ?
question 2): How I put the gun in front of at camera and not at player?

no.

First of all :

http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/CameraNode.html#CameraNode()

You CANNOT use the CameraNode’s empty (no parameter) constructor.

The cameranode is here to grab your camera, to force its position and its location. But, you can also attach node to this camera.

The idea is to have your gun attached to your camera. But you cannot attach the node directly to your camera, because a camera is not a node. So, you use a cameranode, then attach the camera to the cameranode and the weapon to the cameranode.

Right now, you update the camera location each frame, but you doesn’t modify the rotation of the player to match the rotation of the camera. What you must have is :

  1. a player node (let’s call it A)
  2. a children of A (for the head) with a localtranslation of ~(0, 1.8f, 0). Let’s call it B.
  3. a children of B, which is a CameraNode, created with the constructor with 2 parameter. Let’s call it C.
  4. a children of C, which is the weapon (of a weapon placeholder), with a local translation of ~(0.2f, -0.3f, 0.3f).

I personnaly use the method
setControlDir(CameraControl.ControlDirection controlDir)
with the value SpatialToCamera and handle the position of the camera myself, and disable the flycam and handle the rotation of the camera myself.

I follow your sintax , it’s ok ?

[java]
Node B= new Node(“head”);
CameraNode C= new CameraNode(“cameraNode”, cam);
private void initPlayer(){
flyCam.setMoveSpeed(100);
flyCam.setEnabled(true);
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
player = new CharacterControl(capsuleShape, 0.05f);
player.setJumpSpeed(20);
player.setFallSpeed(30);
player.setGravity(30);
bulletAppState.getPhysicsSpace().add(player);

	sword =  (Node) assetManager.loadModel("assets/saiga.blend");
	sword.setLocalScale(0.5f, 0.5f, 0.5f);
    sword.setLocalTranslation(0.2f, -0.3f, 0.3f);
	
   //A IS PLAYER NODE		
    A = new Node("player node");
    A.addControl(player);
    player.setPhysicsLocation(new Vector3f(0, 0, 0));
    //HEAD
    B.setLocalTranslation(0, 1.8f, 0);
    A.attachChild(B);
    B.attachChild(C);
    //CAMERA NODE
    C.attachChild(sword) ;     
    //sword is the weapon
    rootNode.attachChild(A);
}

[/java]

result : I walk with the weapon on my head

why the hell is this out of a function :

CameraNode C= new CameraNode(“cameraNode”, cam);

?

do you know that it means that this is initialized when the object is build, i.e. before anything is assigned to the cam attribute ? So, this is equivalent to new CameraNode(“blabla”, null) which is obviously not going to work.

And you’ll have done one step when you’ll lose the camera control (this because the camera will be attached to the cameranode and the camera rotation will be constraint by the cameranode rotation).

I am a bit angry, not because you don’t understand the api (which can happen and is not a particular problem) but because it seems you have problem to understand how java works (which is a problem).

Also, all the A, B, C etc. is only a mathematical way of naming object i.e. you don’t need to use these names in your program.

I don’t have too much time to dedicated at game and to study tutorial unfortunately,and many times I effect fast modification and go :frowning: For this reason I prefer a gradual approach or a similar test example that in this case I don’t found …I know for the letter, but I modify it for follow you and don’t lose my and your time … For me, it’s very utility a simple similar example I search too much on the web but nothing … In a few day with little time I do more thing but now I’m in block

@ziofedora said: I don't have too much time to dedicated at game and to study tutorial unfortunately,and many times I effect fast modification and go :( For this reason I prefer a gradual approach or a similar test example that in this case I don't found ...I know for the letter, but I modify it for follow you and don't lose my and your time .. For me, it's very utility a simple similar example I search too much on the web but nothing ... In a few day with little time I do more thing but now I'm in block

Hey! You can try my approach with Control.

Take a look at this topic: http://hub.jmonkeyengine.org/forum/topic/controlappstate-update-bug/
Check Control. Only control.
That was my issue descovery. But the example is usable for the Control.

You shoul get the sphere before the camera.Start watching video from 0.45 time :slight_smile:
[video]https://www.youtube.com/watch?feature=player_embedded&v=x87eUW5LRvw#t=46[/video]

First of All thanks very very much for the apprehension :slight_smile: I’m not technically an expert but a BBeginner and I can’t judge it
,but for now your approach help more me and I can work ,so do you think that is it a good way for a first shooter game?

I try to load a weapon and to rotate it, with the cam , it works but it’s horizontal in front of the cam, how can set it correttly?
ps thanks in advance.

[java]

public class AAControl extends AbstractControl {

private Node root;
private Geometry geom;
private Application app;
Node gun;

public AAControl(Application app){
    //TODO: initialize your AppState, e.g. attach spatials to rootNode
    //this is called on the OpenGL thread after the AppState has been attached
    this.app = app;
    //what is rootNode
    root = (Node) app.getViewPort().getScenes().get(0);
    //sphere
    /*
    Sphere b = new Sphere(50, 50, 1);
    geom = new Geometry("Sphere", b);
    Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
    geom.setMaterial(mat);
   */
    gun=(Node) (app.getAssetManager().loadModel("assets/saiga.blend"));
    root.attachChild(gun);
    
    //light 
    DirectionalLight dl = new DirectionalLight();
    dl.setDirection(new Vector3f(-0.8f, -0.6f, -0.08f).normalizeLocal());
    dl.setColor(new ColorRGBA(1, 1, 1, 1));
    root.addLight(dl);
    
    
  
    
    app.getStateManager().getState(FlyCamAppState.class).getCamera().setMoveSpeed(20);
    //set color heaven
    app.getViewPort().setBackgroundColor(ColorRGBA.Blue);
}

@Override
protected void controlUpdate(float tpf) {
	 Camera cam = app.getCamera();
     Vector3f vec = cam.getLocation().add(cam.getDirection().normalize().mult(8f));
     Quaternion rot=   cam.getRotation();
     gun.setLocalTranslation(vec.x,vec.y-5,vec.z);
    
     gun.setLocalRotation( rot);
}

@Override
protected void controlRender(RenderManager rm, ViewPort vp) {

// throw new UnsupportedOperationException(“Not supported yet.”); //To change body of generated methods, choose Tools | Templates.
}
}

[/java]

@ziofedora said: First of All thanks very very much for the apprehension :) I'm not technically an expert but a BBeginner and I can't judge it ,but for now your approach help more me and I can work ,so do you think that is it a good way for a first shooter game?

I try to load a weapon and to rotate it, with the cam , it works but it’s horizontal in front of the cam, how can set it correttly?
ps thanks in advance.

Dunno know what’s your problem. But i think this will help you:
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:math_for_dummies