Listeners inside of a control

I have created a control to handle player movement which contains an action listener and a analog listener. neither of the listeners in the control are ever called. I have instanced the control and attached it to the spatial how do I get the listeners to work?



Thanks.

You have to tell the input manager about it:

inputManager.addListener(yourListenerClass, “leftClick”);

Thanks for the reply. I did tell the input manager about it originally and I just tried another method. The way I was handling it when I posted was right after I set up the keys I added the listeners inside of my control. I rewrote it just now so that the listeners are added in simple initiate app with the same results, the listeners are never called. The other thing I tried is to make the control implement actionListener and analogListener and add the control as the listener to the inputmanager.



Edit: I did find part of my problem I forgot to pass the inputManager to the method I used to create all of the listeners.



I still have one big problem the key input still does not work but the mouse input does.



here the part of the control file that manages listeners and movement.

[java]

private void registerWithInput(InputManager inputManager){

this.inputManager = inputManager;



inputManager.addMapping("Player_Left", new MouseAxisTrigger(MouseInput.AXIS_X, true),

new KeyTrigger(KeyInput.KEY_LEFT));



inputManager.addMapping("Player_Right", new MouseAxisTrigger(MouseInput.AXIS_X, false),

new KeyTrigger(KeyInput.KEY_RIGHT));



inputManager.addMapping("Player_Up", new MouseAxisTrigger(MouseInput.AXIS_Y, false),

new KeyTrigger(KeyInput.KEY_UP));



inputManager.addMapping("Player_Down", new MouseAxisTrigger(MouseInput.AXIS_Y, true),

new KeyTrigger(KeyInput.KEY_DOWN));



inputManager.addMapping("Player_Forward", new KeyTrigger(KeyInput.KEY_W));

inputManager.addMapping("Player_Backward", new KeyTrigger(KeyInput.KEY_S));

inputManager.addMapping("Player_StrafeLeft", new KeyTrigger(KeyInput.KEY_A));

inputManager.addMapping("Player_StrafeRight", new KeyTrigger(KeyInput.KEY_D));

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



inputManager.addListener(this, mappings);



}

public void onAnalog(String name, float value, float tpf) {

System.out.println("hi");

if (name.equals("Player_Left")){

rotatePlayer(value, getUp());

}else if (name.equals("Player_Right")){

rotatePlayer(-value, getUp());

}else if (name.equals("Player_Up")){

rotatePlayer(-value, getLeft());

}else if (name.equals("Player_Down")){

rotatePlayer(value, getLeft());

}else if (name.equals("Player_Forward")){

movePlayer(value, false);

}else if (name.equals("Player_Backward")){

movePlayer(-value, false);

}else if (name.equals("Player_StrafeLeft")){

movePlayer(value, true);

}else if (name.equals("Player_StrafeRight")){

movePlayer(-value, true);

}

}



public void onAction(String binding, boolean value, float tpf) {

System.out.println("ho");

/**if (binding.equals("Player_StrafeLeft")) {

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

} else if (binding.equals("Player_StrafeRight")) {

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

} else if (binding.equals("Player_Forward")) {

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

} else if (binding.equals("Player_Backward")) {

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

} else if (binding.equals("Jump")) {

playerControl.jump();

}



playerDirection.set(Vector3f.ZERO.add(getDirection().x , 0, getDirection().z));

Vector3f playerLeft = getLeft().clone().multLocal(0.4f);

walkDirection.set(0, 0, 0);

if (left) { walkDirection.addLocal(playerLeft); }

if (right) { walkDirection.addLocal(playerLeft.negate()); }

if (up) { walkDirection.addLocal(playerDirection); }

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

playerControl.setWalkDirection(walkDirection);

spatial.setLocalTranslation(playerControl.getPhysicsLocation());*/

}



private void movePlayer(float value, boolean b) {

Vector3f vel = new Vector3f(); //I think this vector is part of the movement problem.

Vector3f pos = spatial.getLocalTranslation().clone();

sideways = b;



if (sideways){

getLeft(vel);

}else{

getDirection(vel);

}

vel.multLocal(value * moveSpeed);



walkDirection.addLocal(vel);//this line is unnecessary if walkDirection is not modified anywhere else.

playerControl.setWalkDirection(vel);

spatial.setLocalTranslation(playerControl.getPhysicsLocation());

}



private void rotatePlayer(float value, Vector3f axis) {

Matrix3f mat = new Matrix3f();

mat.fromAngleNormalAxis(rotationSpeed * value, axis);



Vector3f up = getUp();

Vector3f left = getLeft();

Vector3f dir = getDirection();



mat.mult(up, up);

mat.mult(left, left);

mat.mult(dir, dir);



Quaternion q = new Quaternion();

q.fromAxes(left, up, dir);

q.normalizeLocal();



setAxes(q);

}[/java]



Thanks for the help.

Does your class also implement ActionListener?

is the variable “mappings” set correctly?

1 Like

Thanks for the replies.



@Spolerq The class does implement ActionListener and AnalogListener.



@wexrule here is my mappings variable I believe it is correct.



[java]private static String[] mappings = new String[]{

"Player_Left",

"Player_Right",

"Player_Up",

"Player_Down",



"Player_StrafeLeft",

"Player_StrafeRight",

"Player_Forward",

"Player_Backward",

"Jump"

};[/java]



Sorry I did not reply sooner I was gone all day. :slight_smile:

And because it pays to check: How are you determining that your listener is never called? (sorry, I had to ask.)



edit: nevermind, I see the println now. I’ll follow up in a sec with something else.

Can we see the whole class by any chance? Your code is acting exactly like if you didn’t implement ActionListener.



You can also add the appropriate “@Override” annotations to your onXXX methods and make sure it still compiles.

I have implemented actionlistener and analog listener. I added the @overrides and I found that both of my listeners are now responding to input but for some reason the keyboard events are not causing my spatial to move, as far as I can tell they should work.



one more question related to this how do you trap the mouse in the screen?



here is the entire class:



[java]import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

import com.jme3.bullet.control.CharacterControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.collision.MotionAllowedListener;

import com.jme3.export.JmeExporter;

import com.jme3.export.JmeImporter;

import com.jme3.export.Savable;

import com.jme3.input.InputManager;

import com.jme3.input.JoyInput;

import com.jme3.input.Joystick;

import com.jme3.input.KeyInput;

import com.jme3.input.MouseInput;

import com.jme3.input.controls.*;

import com.jme3.math.Matrix3f;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.renderer.RenderManager;

import com.jme3.renderer.ViewPort;

import com.jme3.scene.Spatial;

import com.jme3.scene.control.AbstractControl;

import com.jme3.scene.control.Control;

import java.io.IOException;



public class PlayerMoveControl extends AbstractControl implements Savable, Cloneable, ActionListener, AnalogListener{

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

private BulletAppState bulletAppState;

private CharacterControl playerControl;

private float rotationSpeed = 1f;

private float moveSpeed = 3f;

private MotionAllowedListener motionAllowed = null;

private boolean moveEnabled = true;

private boolean canRotate = true;

private InputManager inputManager;

Vector3f playerDirection = new Vector3f();

Vector3f walkDirection = new Vector3f();



private static String[] mappings = new String[]{

"Player_Left",

"Player_Right",

"Player_Up",

"Player_Down",



"Player_StrafeLeft",

"Player_StrafeRight",

"Player_Forward",

"Player_Backward",

"Jump"

};

private boolean sideways;

private boolean value;





public PlayerMoveControl(BulletAppState bulletAppState, InputManager inputManager, CharacterControl playerControl){

this.bulletAppState = bulletAppState;

this.inputManager = inputManager;

this.inputManager.setCursorVisible(false);

this.playerControl = playerControl;

registerWithInput(inputManager);



playerControl.setJumpSpeed(20);

playerControl.setFallSpeed(50);

playerControl.setGravity(40);

bulletAppState.getPhysicsSpace().add(playerControl);

playerControl.setPhysicsLocation(new Vector3f(0, 10, 30));

//TODO: fix fall speed acceleration



}

@Override

public void setSpatial(Spatial spatial) {

super.setSpatial(spatial);

}





@Override

protected void controlUpdate(float tpf){

if(spatial != null) {

spatial.setLocalTranslation(playerControl.getPhysicsLocation());

}

}



/**

  • Registers the FlyByCamera to receive input events from the provided
  • Dispatcher.
  • @param inputManager

    /

    private void registerWithInput(InputManager inputManager){

    this.inputManager = inputManager;



    inputManager.addMapping("Player_Left", new MouseAxisTrigger(MouseInput.AXIS_X, true),

    new KeyTrigger(KeyInput.KEY_LEFT));



    inputManager.addMapping("Player_Right", new MouseAxisTrigger(MouseInput.AXIS_X, false),

    new KeyTrigger(KeyInput.KEY_RIGHT));



    inputManager.addMapping("Player_Up", new MouseAxisTrigger(MouseInput.AXIS_Y, false),

    new KeyTrigger(KeyInput.KEY_UP));



    inputManager.addMapping("Player_Down", new MouseAxisTrigger(MouseInput.AXIS_Y, true),

    new KeyTrigger(KeyInput.KEY_DOWN));



    inputManager.addMapping("Player_Forward", new KeyTrigger(KeyInput.KEY_W));

    inputManager.addMapping("Player_Backward", new KeyTrigger(KeyInput.KEY_S));

    inputManager.addMapping("Player_StrafeLeft", new KeyTrigger(KeyInput.KEY_A));

    inputManager.addMapping("Player_StrafeRight", new KeyTrigger(KeyInput.KEY_D));

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



    inputManager.addListener(this, mappings);



    }

    public void onAnalog(String name, float value, float tpf) {

    System.out.println("hi");

    if (name.equals("Player_Left")){

    rotatePlayer(value, getUp());

    }else if (name.equals("Player_Right")){

    rotatePlayer(-value, getUp());

    }else if (name.equals("Player_Up")){

    rotatePlayer(-value, getLeft());

    }else if (name.equals("Player_Down")){

    rotatePlayer(value, getLeft());

    }else if (name.equals("Player_Forward")){

    movePlayer(value, false);

    }else if (name.equals("Player_Backward")){

    movePlayer(-value, false);

    }else if (name.equals("Player_StrafeLeft")){

    movePlayer(value, true);

    }else if (name.equals("Player_StrafeRight")){

    movePlayer(-value, true);

    }

    }



    public void onAction(String binding, boolean value, float tpf) {

    System.out.println("ho");

    /**if (binding.equals("Player_StrafeLeft")) {

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

    } else if (binding.equals("Player_StrafeRight")) {

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

    } else if (binding.equals("Player_Forward")) {

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

    } else if (binding.equals("Player_Backward")) {

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

    } else if (binding.equals("Jump")) {

    playerControl.jump();

    }



    playerDirection.set(Vector3f.ZERO.add(getDirection().x , 0, getDirection().z));

    Vector3f playerLeft = getLeft().clone().multLocal(0.4f);

    walkDirection.set(0, 0, 0);

    if (left) { walkDirection.addLocal(playerLeft); }

    if (right) { walkDirection.addLocal(playerLeft.negate()); }

    if (up) { walkDirection.addLocal(playerDirection); }

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

    playerControl.setWalkDirection(walkDirection);

    spatial.setLocalTranslation(playerControl.getPhysicsLocation());
    /

    }



    private void movePlayer(float value, boolean b) {

    Vector3f vel = new Vector3f();

    Vector3f pos = spatial.getLocalTranslation().clone();

    sideways = b;



    if (sideways){

    getLeft(vel);

    }else{

    getDirection(vel);

    }

    vel.multLocal(value * moveSpeed);



    walkDirection.addLocal(vel);//this line is unnecessary if walkDirection is not modified anywhere else.

    playerControl.setWalkDirection(vel);

    spatial.setLocalTranslation(playerControl.getPhysicsLocation());

    }

    }



    private void rotatePlayer(float value, Vector3f axis) {

    Matrix3f mat = new Matrix3f();

    mat.fromAngleNormalAxis(rotationSpeed * value, axis);



    Vector3f up = getUp();

    Vector3f left = getLeft();

    Vector3f dir = getDirection();



    mat.mult(up, up);

    mat.mult(left, left);

    mat.mult(dir, dir);



    Quaternion q = new Quaternion();

    q.fromAxes(left, up, dir);

    q.normalizeLocal();



    setAxes(q);

    }



    public void unregisterInput(){



    if (inputManager == null) {

    return;

    }



    for (String s : mappings) {

    if (inputManager.hasMapping(s)) {

    inputManager.deleteMapping( s );

    }

    }



    inputManager.removeListener(this);

    inputManager.setCursorVisible(true);



    Joystick[] joysticks = inputManager.getJoysticks();

    if (joysticks != null && joysticks.length > 0){

    Joystick joystick = joysticks[0];



    }

    }



    /**
  • <code>getDirection</code> retrieves the direction vector the player is
  • facing.

    *
  • @return the direction the player is facing.
  • @see PlayerNode#getDirection()

    */

    private Vector3f getDirection() {

    return spatial.getLocalRotation().getRotationColumn(2);

    }

    /**
  • <code>getLocation</code> retrieves the location vector of the player.

    *
  • @return the position of the player.
  • @see PlayerNode#getLocation()

    */

    private Vector3f getDirection(Vector3f store) {

    return spatial.getLocalRotation().getRotationColumn(2, store);

    }



    /**
  • <code>getLeft</code> retrieves the left axis of the player.

    *
  • @return the left axis of the player.
  • @see PlayerNode#getLeft()

    */

    private Vector3f getLeft() {

    return spatial.getLocalRotation().getRotationColumn(0);

    }



    /**
  • <code>getLeft</code> retrieves the left axis of the player.

    *
  • @return the left axis of the player.
  • @see PlayerNode#getLeft()

    */

    private Vector3f getLeft(Vector3f store) {

    return spatial.getLocalRotation().getRotationColumn(0, store);

    }



    /**
  • <code>getUp</code> retrieves the up axis of the player.

    *
  • @return the up axis of the player.
  • @see PlayerNode#getUp()

    */

    public Vector3f getUp() {

    return spatial.getLocalRotation().getRotationColumn(1);

    }



    /**
  • <code>getUp</code> retrieves the up axis of the player.

    *
  • @return the up axis of the player.
  • @see PlayerNode#getUp()

    */

    public Vector3f getUp(Vector3f store) {

    return spatial.getLocalRotation().getRotationColumn(1, store);

    }



    /**
  • <code>setAxes</code> sets the axes (left, up and direction) for this
  • player.

    *
  • @param left the left axis of the player.
  • @param up the up axis of the player.
  • @param direction the direction the player is facing.

    *
  • @see PlayerNode#setAxes(com.jme3.math.Quaternion)

    */

    public void setAxes(Vector3f left, Vector3f up, Vector3f direction) {

    Quaternion fromAxisQuaternion = new Quaternion();

    fromAxisQuaternion.fromAxes(left, up, direction);

    spatial.setLocalRotation(fromAxisQuaternion);

    }



    /**
  • <code>setAxes</code> uses a rotational matrix to set the axes of the
  • player.

    *
  • @param axes the matrix that defines the orientation of the player.

    */

    public void setAxes(Quaternion axes) {

    spatial.setLocalRotation(axes);

    }



    /**
  • <code>setLocation</code> sets the position of the player.

    *
  • @param location the position of the player.

    */

    private void setLocation(Vector3f pos) {

    spatial.setLocalTranslation(pos);

    }



    @Override

    protected void controlRender(RenderManager rm, ViewPort vp) {

    }



    @Override

    public Control cloneForSpatial(Spatial spatial) {

    throw new UnsupportedOperationException("Not supported yet.");

    }



    public String[] getMappingNames(){

    String[] m = mappings.clone();

    return m;

    }

    }[/java]



    Thanks.

The move player method is being called. I just realized that the movement was so slow that I could not see it. :slight_smile: I set the moveSpeed variable to 50f now it moves more noticeably still acts a little weird though. Once a direction is pressed the spatial will continue in that direction until another direction is pressed. I am going to play with the mechanics of the movement for a while and will post back here if I can’t figure it out after a few days.



two more questions real quick:



How do I trap the mouse in the screen?



How do I disengage an action inside of the analog listener once the key is no longer pressed?



Thanks for all the help.

@darklightning7 said:
How do I disengage an action inside of the analog listener once the key is no longer pressed?


The analog listener is only called while the key is pressed. When the key is released, the onAnalog method is not called anymore for that key.

If you need the up and down events then you should use the action listener part.

Is your move method being called? If it were me, I’d put a bunch of printlns in there to see what’s happening.

After reading your post I realized what is happening when the analogListener is no longer being called. I do have one more issue that is making it hard to test my code the mouse is not trapped inside of the window. It is allowed to move out side of the program window after which it no longer affects the program and the mouse is visible when it is over the window. Any Ideas on what causes this?



Thanks for the help.

What is the obsession of “trapping the mouse” in the window these days?



The only way to do this is by listening to the mouse movement and constraining it manually if it goes out of bound. Note that it is really bad form to do this in windowed mode. If the user decide to play your game in windowed mode it’s their responsibility to click inside the game window.

It is a first person game the head is controlled by the mouse so unless its trapped inside of the window you can only move your head a little way less than 10 degrees in any direction.

The mouse is automatically made transparent and trapped inside of the window in the tutorials and I can’t figure out what part of my code would change that effect.



Edit: I think part of the problem might be that the tutorials use the fly camera to control movement and I am using a custom node.



Thanks for the reply.

@darklightning7 said:
It is a first person game the head is controlled by the mouse so unless its trapped inside of the window you can only move your head a little way less than 10 degrees in any direction.
The mouse is automatically made transparent and trapped inside of the window in the tutorials and I can't figure out what part of my code would change that effect.

Thanks for the reply.

So I guess this would be like in Minecraft when you're not in interaction mode with inventory and stuff. That's fine. I have nothing against that, but, when the cursor is free, it shouldn't be constrained inside the game window. That's not your responsibility. If the user is too dumb (or unlucky) that's his problem, not yours. ;) If he doesn't like that he can always switch to fullscreen.

With that said, you can use

[java]
inputManager.setCursorVisible(false);
[/java]

to disable the cursor while in that mode.

The problem is that the cursor is never inside of the game it only affects it when it is over the window and does not disappear when the window is selected. When I first had this problem I tried setting the cursor visibility to false but that had no effect. It is acting like a program such as word or a web browser, where you can move the cursor out of the game without pausing, opening inventory, hitting the windows key, ect. Once the cursor is outside of the boundaries of the window it has no effect on the game.



Thanks.

@darklightning7 said:
The problem is that the cursor is never inside of the game it only affects it when it is over the window and does not disappear when the window is selected. When I first had this problem I tried setting the cursor visibility to false but that had no effect. It is acting like a program such as word or a web browser, where you can move the cursor out of the game without pausing, opening inventory, hitting the windows key, ect. Once the cursor is outside of the boundaries of the window it has no effect on the game.

Thanks.


Does it do this with the standard fly cam? Because I think this works pretty well for everyone else.

I am not completely sure what you are asking but here is my best guess on an answer.



I am using the standard fly cam to render the scene but I am not using it to control movement.



Thanks

@darklightning7 said:
The problem is that the cursor is never inside of the game...

What do you mean? the cursor is never inside the game window? :?


it only affects it when it is over the window and does not disappear when the window is selected.

Define affect please. What kind of behavior do you expect the game to have when the mouse is outside the bound of the game screen and doesn't have the focus? No application reacts to input when the mouse is outside the window and it doesn't have the focus. That's normal. It doesn't have the focus thus should not get input messages.


When I first had this problem I tried setting the cursor visibility to false but that had no effect. It is acting like a program such as word or a web browser, where you can move the cursor out of the game without pausing, opening inventory, hitting the windows key, ect. Once the cursor is outside of the boundaries of the window it has no effect on the game.


I'm reading conflicting things here. You talk about mouse being outside the window and the window being "selected" (which I imagine you mean giving it the focus).

- If an application has the focus but mouse is outside its window, no mouse behavior is triggered since the mouse is outside the application's boundary. But, input should still be directed to the application IF it has the focus.
- If an application doesn't have focus and mouse is outside, nothing should be triggered inside the app since nothing is sent to the application; it doesn't have the focus. You can test that with any application.

Anyway, it's entirely possibly I'm not understanding you problem. Maybe a concrete example would help.