First Person Camera MouseAxisTrigger not working?

Hello all. So I am going through the wiki and reading some books on JMonkey programming and was trying to implement a first person camera using Camera node with Mouse movement for the view. I can’t quite seem to understand why the camera view isnt working. I have WASD forward,back,strafing working but just not mouse movement. My screen still shows the mouse cursor and doesn’t move the camera when i move the mouse. Can you tell me what it is I am missing or not understanding about camera movement with a mouse and the camera node? I haven’t implemented up/down yet as I was working on Left/Right first. After this I am going to test/learn about the Chase Cam but wanted to understand this version first.

Here is the code:

public class PhysicsTown extends SimpleApplication  {

    private Node sceneNode;
    private BulletAppState bulletAppState;
    private RigidBodyControl scenePhysics;
    private Node playerNode;
    private BetterCharacterControl playerControl;
    private CameraNode camNode;
    private Vector3f walkDirection = new Vector3f(0,0,0);
    private Vector3f viewDirection = new Vector3f(0,0,1);
    private boolean viewLeft = false, viewRight = false, forward = false, backward = false, left = false, right = false, 
            viewUp = false, viewDown = false;
    private float speed = 8;
    private float yaw = 0;
    public static void main(String[] args) {
        PhysicsTown app = new PhysicsTown();

    public void simpleInitApp() {
        //Load the Town Scene
        assetManager.registerLocator("", ZipLocator.class);
        sceneNode = (Node)assetManager.loadModel("main.scene");
        //Create Ambient Light
        AmbientLight ambient = new AmbientLight();
        //Create Directional lighting
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(1.4f, -1.4f, -1.4f));
        //Increase Camera Speed
        //Set the sky to blue
        //Add Physics to the Scene as to not clip through walls and the floor
        bulletAppState = new BulletAppState();
        scenePhysics = new RigidBodyControl(0f);
        //Making the camera solid
        playerNode = new Node("the player");
        playerNode.setLocalTranslation(new Vector3f(0, 6, 0));
        playerControl = new BetterCharacterControl(1.5f, 4, 30f);
        playerControl.setJumpForce(new Vector3f(0, 300, 0));
        playerControl.setGravity(new Vector3f(0, -10, 0));
        camNode = new CameraNode("CamNode", cam);
        camNode.setLocalTranslation(new Vector3f(0,4,-6));
        Quaternion quat = new Quaternion();
        quat.lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y);
        //Create Key Mappings
        inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Back", new KeyTrigger(KeyInput.KEY_S));
        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("View Left", new MouseAxisTrigger(MouseInput.AXIS_X, true));
        inputManager.addMapping("View Right", new MouseAxisTrigger(MouseInput.AXIS_X, false));
        inputManager.addMapping("View Up", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
        inputManager.addMapping("View Down", new MouseAxisTrigger(MouseInput.AXIS_Y, false));
        //Create Listeners
        inputManager.addListener(analogListener, "View Left", "View Right", "View Up", "View Down");
        inputManager.addListener(actionListener, "Forward", "Back", "Jump", "Left", "Right");
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String binding, boolean isPressed, float tpf) {
            if (binding.equals("Forward")) {
                forward = isPressed;
            } else if (binding.equals("Back")) {
                backward = isPressed;
            } else if (binding.equals("Jump")) {
            } else if (binding.equals("Left")) {
                left = isPressed;
            } else if (binding.equals("Right")) {
                right = isPressed;
    private AnalogListener analogListener = new AnalogListener() {
        public void onAnalog(String name, float value, float tpf) {
            if (name.equals("View Left")) {
                rotate(tpf * value);
            } else if (name.equals("View Right")) {
              rotate(-tpf * value);
            } else if(name.equals("View Up")){
            } else if (name.equals("LookDown")){
            } else if (name.equals("View Down")) {
                speed = value * 3;
    public void rotate(float value) {
        Quaternion rotate = new Quaternion().fromAngleAxis(FastMath.PI * value, Vector3f.UNIT_Y);
    protected void lookUpDown(float value) {
        yaw += value;
        yaw = FastMath.clamp(yaw, -FastMath.HALF_PI, FastMath.HALF_PI);
        playerControl.setViewDirection(new Vector3f(yaw, 0, 0));
    public void simpleUpdate(float tpf) {
        //Get Current foward and left vectors of the player node
        Vector3f modelForwardDir = playerNode.getWorldRotation().mult(Vector3f.UNIT_Z);
        Vector3f modelLateralDir = playerNode.getWorldRotation().mult(Vector3f.UNIT_X);
        Vector3f modelLeftDir = playerNode.getWorldRotation().mult(Vector3f.UNIT_X);
        //Determine the change in direction
        walkDirection.set(0, 0, 0);
        if (forward) {
        } else if (backward) {
        } else if (right) {
        } else if (left) {
        playerControl.setWalkDirection(walkDirection); //walk!        


    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    /** A plus sign used as crosshairs to help the player with aiming.*/
    protected void initCrossHairs() {
      guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
      BitmapText 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);


I can see I can get rid of the mouse cursor by using

But only when I comment out the flycam code

I guess I don’t have enough experience to know if I can use flyCam along with a CameraNode?

With my code if i load the program and use WASD first it works fine, the second i try and move the mouse, WASD stops working as well. So I obviously did something very wrong.

Thanks for any insight!

Well, flyCam is going to be doing a bunch of stuff that you are also trying to do… best to just remove it completely to avoid the issue. Get the FlyCamAppState from the state manager and then remove it.

Then if things still aren’t working, put some System.out.printlns in your analog listener to see if it’s even being called, etc…

Ok thanks, I added the following which did remove the cursor.


I had print statements and the analogListener is definitely working. When I move the mouse the actionlistener is printing up,down,left,right. And the camera is moving but very very little. Maybe its a camera speed issue?

Edit: Ok when I remove the tpf float from the rotate(tpf * value); it rotates quickly. I still need to look into why the heck walkDirection stops working after mouse movement. Action listener & simple update are still registering its just the character doesnt move with wasd.

Thanks again for the help!

Edit 2:
I think im getting the hang of it. The issue with movement is in the math. Apparently BetterCharacterControl uses TPF internally so i need to better match the speed all around.

Yeah, JME premultiplies the mouse movement by tpf before delivering it to analog listeners… an unfortunately decision in my opinion but it does it. (Lemur’s InputMapper mouse handling doesn’t do this, by the way, which means mouse input can be used just like any other input.)

Per frame movement would still need to be multiplied by tpf or it would be frame rate dependent.