Before you put too much effort into this, wait a minute. I’ll show you s’thing.
public class ThirdPersonHandler extends InputHandler {
/**
* Keeps the reference to the node moving action, which is always called.
*/
private MoveNodeAction internalNodeAction;
/**
* Keeps the reference to the avatar root node.
*/
private Spatial avatarNode;
public ThirdPersonHandler(AbstractGame app, Camera cam, Spatial avatar,
String api) {
avatarNode = avatar;
setKeyBindings(api);
setMouse(cam);
setActions(cam, app);
}
private void setKeyBindings(String api) {
KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
InputSystem.createInputSystem(api);
keyboard.setKeyInput(InputSystem.getKeyInput());
keyboard.set("screenshot", KeyInput.KEY_F12);
keyboard.set("exit", KeyInput.KEY_ESCAPE);
KeyBindingManager.getKeyBindingManager().set("node_forw",
KeyInput.KEY_UP);
KeyBindingManager.getKeyBindingManager().set("node_back",
KeyInput.KEY_DOWN);
KeyBindingManager.getKeyBindingManager().set("node_left",
KeyInput.KEY_LEFT);
KeyBindingManager.getKeyBindingManager().set("node_right",
KeyInput.KEY_RIGHT);
setKeyBindingManager(keyboard);
/* create instance of my own move action */
internalNodeAction = new MoveNodeAction(avatarNode, 6f);
}
private void setMouse(Camera cam) {
RelativeMouse mouse = new RelativeMouse("Mouse Input");
mouse.setMouseInput(InputSystem.getMouseInput());
setMouse(mouse);
}
private void setActions(Camera cam, AbstractGame app) {
KeyExitAction exit = new KeyExitAction(app);
exit.setKey("exit");
addAction(exit);
KeyScreenShotAction screen = new KeyScreenShotAction();
screen.setKey("screenshot");
addAction(screen);
}
public void update(float time) {
/* call base class method */
super.update(time);
/* collect pressed keys in a bit mask */
int direction = 0;
if (keyboard.isValidCommand("node_forw")) {
direction |= MoveNodeAction.FORWARD;
}
if (keyboard.isValidCommand("node_back")) {
direction |= MoveNodeAction.BACKWARD;
}
if (keyboard.isValidCommand("node_left")) {
direction |= MoveNodeAction.STRAFELEFT;
}
if (keyboard.isValidCommand("node_right")) {
direction |= MoveNodeAction.STRAFERIGHT;
}
if (direction != 0) {
/* set the direction value */
internalNodeAction.setDirection(direction);
/* and perform the update */
internalNodeAction.performAction(time);
}
}
}
That's my current input handler.
public class MoveNodeAction extends AbstractInputAction {
private Spatial avatarNode;
public static final int FORWARD = 1;
public static final int BACKWARD = 2;
public static final int STRAFELEFT = 4;
public static final int STRAFERIGHT = 8;
private int direction = FORWARD;
private static final float ADJUST = FastMath.sqrt(2);
/**
* Constructor creates a new <code>KeyNodeForwardAction</code> object.
* During construction, the node to direct and the speed at which to move
* the node is set.
*
* @param node
* the node that will be affected by this action.
* @param speed
* the speed at which the camera can move.
*/
public MoveNodeAction(Spatial node, float speed) {
this.avatarNode = node;
this.speed = speed;
}
public void setDirection(int newDirection) {
direction = newDirection;
}
/**
* <code>performAction</code> moves the node along it's positive direction
* vector at a speed of movement speed * time. Where time is the time
* between frames and 1 corresponds to 1 second.
*
* @see com.jme.input.action.InputAction#performAction(float)
*/
public void performAction(float time) {
Vector3f loc = avatarNode.getLocalTranslation();
Vector3f old = new Vector3f(loc.x, loc.y, loc.z);
// we need to use the rotation of the torso!!
Spatial rotationNode = ((BotTest)avatarNode).getBody();
Quaternion quat = rotationNode.getLocalRotation();
Vector3f currTranslation = new Vector3f(0f, 0f, 0f);
Vector3f rotCol = null;
float localSpeed = speed;
/*
* direction will be != 0; now if it is unequal to any single constant,
* it must be a combination
*/
if (direction != FORWARD && direction != BACKWARD
&& direction != STRAFELEFT && direction != STRAFERIGHT) {
localSpeed /= ADJUST;
}
/* next calculate the current translation */
if ((direction & FORWARD) != 0) {
rotCol = quat.getRotationColumn(2);
currTranslation = currTranslation.addLocal(rotCol.mult((localSpeed * time)));
}
if ((direction & BACKWARD) != 0) {
rotCol = quat.getRotationColumn(2);
currTranslation = currTranslation.addLocal(rotCol.mult((-localSpeed * time)));
}
if ((direction & STRAFELEFT) != 0) {
rotCol = quat.getRotationColumn(0);
currTranslation = currTranslation.addLocal(rotCol
.multLocal((localSpeed * time)));
}
if ((direction & STRAFERIGHT) != 0) {
rotCol = quat.getRotationColumn(0);
currTranslation = currTranslation.addLocal(rotCol
.multLocal((-localSpeed * time)));
}
loc.addLocal(currTranslation);
/*
* this is the place, where collision detection will have to adjust
* loct
*/
/* whatever remains, gets set as the local translation */
avatarNode.setLocalTranslation(loc);
}
}
And that's my current action. The thing about the rotation node is that I don't want to use the orientation of the avatars root node but of some child node so that's a detail.
This thing works. It's ugly, but it does, what I plan to do. And I don't need key definitions inside the action. On the other hand, it is no longer a simple action, since it relies on the setDirection call.