I've read several separate threads from people looking for the same thing: a good InputHandler for Physics first-person-shooters.
The problem with just using a NodeHandler on a CameraNode with the model attached is that if you look up or down, the character will rotate so it's body is looking up.
Has there been a solution for this problem, so that the character's body will rotate right/left, but only the head (or just the camera, even) will rotate up/down?
None of the people who had the same problem posted their solutions, and the posts are so old I figure it'd be better to start a new one (at least that's what the forum recommended ;))
Help is appreciated.
Also the Handler will need to control a DynamicPhysicsNode, so collision detection works!
I've attempted to suppress the up/down controls by creating a few new classes. They are the same to what NodeHandler uses in every way, except that the up/down references have been completely removed. Somehow, though, it manages to still move the robot up and down!
Any help is appreciated:
package physicsblaster;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.RelativeMouse;
import com.jme.input.action.KeyNodeBackwardAction;
import com.jme.input.action.KeyNodeForwardAction;
import com.jme.input.action.KeyNodeLookDownAction;
import com.jme.input.action.KeyNodeLookUpAction;
import com.jme.input.action.KeyNodeRotateLeftAction;
import com.jme.input.action.KeyNodeRotateRightAction;
import com.jme.input.action.KeyNodeStrafeLeftAction;
import com.jme.input.action.KeyNodeStrafeRightAction;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
/**
* <code>NodeHandler</code> defines an InputHandler that sets
* a node that can be controlled via keyboard and mouse inputs. By default the
* commands are, WSAD moves the node forward, backward and strafes. The
* arrow keys rotate and tilt the node and the mouse also rotates and tilts
* the node.
* @author Mark Powell
* @version $Id: NodeHandler.java,v 1.15 2006/03/05 10:43:57 irrisor Exp $
*/
public class PhysicsFPSHandler extends InputHandler {
/**
* Constructor instantiates a new <code>NodeHandler</code> object. The
* application is set for the use of the exit action. The node is set to
* control, while the api defines which input api is to be used.
* @param node the node to control.
* @param api not used
*/
public PhysicsFPSHandler(Spatial node) { //todo: remove parameter api
setKeyBindings();
setUpMouse(node, 1 );
setActions(node, 0.5f, 0.01f );
}
/**
* Constructor instantiates a new <code>NodeHandler</code> object. The
* application is set for the use of the exit action. The node is set to
* control, while the api defines which input api is to be used.
* @param node the node to control.
* @param keySpeed action speed for key actions (move)
* @param mouseSpeed action speed for mouse actions (rotate)
*/
public PhysicsFPSHandler(Spatial node, float keySpeed, float mouseSpeed) {
setKeyBindings();
setUpMouse(node, mouseSpeed );
setActions(node, keySpeed, mouseSpeed );
}
/**
*
* <code>setKeyBindings</code> binds the keys to use for the actions.
*/
private void setKeyBindings() {
KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
keyboard.set("forward", KeyInput.KEY_W);
keyboard.set("backward", KeyInput.KEY_S);
keyboard.set("strafeLeft", KeyInput.KEY_A);
keyboard.set("strafeRight", KeyInput.KEY_D);
keyboard.set("turnRight", KeyInput.KEY_RIGHT);
keyboard.set("turnLeft", KeyInput.KEY_LEFT);
}
/**
*
* <code>setUpMouse</code> sets the mouse look object.
* @param node the node to use for rotations.
* @param mouseSpeed
*/
private void setUpMouse( Spatial node, float mouseSpeed ) {
mouse = new RelativeMouse("Mouse Input");
mouse.registerWithInputHandler( this );
PhysicsNodeMouseLook mouseLook = new PhysicsNodeMouseLook(mouse, node, 0.1f);
mouseLook.setSpeed( mouseSpeed );
mouseLook.setLockAxis(new Vector3f(node.getLocalRotation().getRotationColumn(1).x,
node.getLocalRotation().getRotationColumn(1).y,
node.getLocalRotation().getRotationColumn(1).z));
addAction(mouseLook);
}
/**
*
* <code>setActions</code> sets the keyboard actions with the corresponding
* key command.
* @param node the node to control.
* @param moveSpeed
* @param turnSpeed
*/
private void setActions( Spatial node, float moveSpeed, float turnSpeed ) {
addAction( new KeyNodeForwardAction( node, moveSpeed ), "forward", true );
addAction( new KeyNodeBackwardAction( node, moveSpeed ), "backward", true );
addAction( new KeyNodeStrafeLeftAction( node, moveSpeed ), "strafeLeft", true );
addAction( new KeyNodeStrafeRightAction( node, moveSpeed ), "strafeRight", true );
KeyNodeRotateRightAction rotateRight = new KeyNodeRotateRightAction( node, turnSpeed );
rotateRight.setLockAxis( node.getLocalRotation().getRotationColumn( 1 ) );
addAction( rotateRight, "turnRight", true );
KeyNodeRotateLeftAction rotateLeft = new KeyNodeRotateLeftAction( node, turnSpeed );
rotateLeft.setLockAxis( node.getLocalRotation().getRotationColumn( 1 ) );
addAction( rotateLeft, "turnLeft", true );
}
}
package physicsblaster;
import com.jme.input.Mouse;
import com.jme.input.action.InputActionEvent;
import com.jme.input.action.KeyNodeRotateLeftAction;
import com.jme.input.action.KeyNodeRotateRightAction;
import com.jme.input.action.MouseInputAction;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
/**
* <code>NodeMouseLook</code> defines a mouse action that detects mouse
* movement and converts it into node rotations and node tilts.
*
* @author Mark Powell
* @version $Id: NodeMouseLook.java,v 1.14 2006/07/22 20:59:10 renanse Exp $
*/
public class PhysicsNodeMouseLook extends MouseInputAction {
//the actions that handle looking up, down, left and right.
private KeyNodeRotateLeftAction rotateLeft;
private KeyNodeRotateRightAction rotateRight;
//the axis to lock
private Vector3f lockAxis;
//the node to control
private Spatial node;
//the event to distribute to the look actions.
private static InputActionEvent event;
/**
* Constructor creates a new <code>NodeMouseLook</code> object. It takes
* the mouse, node and speed of the looking.
*
* @param mouse
* the mouse to calculate view changes.
* @param node
* the node to move.
* @param speed
* the speed at which to alter the camera.
*/
public PhysicsNodeMouseLook(Mouse mouse, Spatial node, float speed) {
this.mouse = mouse;
this.speed = speed;
this.node = node;
rotateLeft = new KeyNodeRotateLeftAction(this.node, speed);
rotateRight = new KeyNodeRotateRightAction(this.node, speed);
event = new InputActionEvent();
}
/**
*
* <code>setLockAxis</code> sets the axis that should be locked down. This
* prevents "rolling" about a particular axis. Typically, this is set to the
* mouse's up vector.
*
* @param lockAxis
* the axis that should be locked down to prevent rolling.
*/
public void setLockAxis(Vector3f lockAxis) {
this.lockAxis = lockAxis;
rotateLeft.setLockAxis(lockAxis);
rotateRight.setLockAxis(lockAxis);
}
/**
* Returns the axis that is currently locked.
*
* @return The currently locked axis
* @see #setLockAxis(com.jme.math.Vector3f)
*/
public Vector3f getLockAxis() {
return lockAxis;
}
/**
*
* <code>setSpeed</code> sets the speed of the mouse look.
*
* @param speed
* the speed of the mouse look.
*/
public void setSpeed(float speed) {
super.setSpeed( speed );
rotateRight.setSpeed(speed);
rotateLeft.setSpeed(speed);
}
/**
* <code>performAction</code> checks for any movement of the mouse, and
* calls the appropriate method to alter the node's orientation when
* applicable.
*
* @see com.jme.input.action.MouseInputAction#performAction(InputActionEvent)
*/
public void performAction(InputActionEvent evt) {
float time = 0.01f * speed;
if (mouse.getLocalTranslation().x > 0) {
event.setTime(time * mouse.getLocalTranslation().x);
rotateRight.performAction(event);
} else if (mouse.getLocalTranslation().x < 0) {
event.setTime(time * mouse.getLocalTranslation().x * -1);
rotateLeft.performAction(event);
}
}
}
It still directly sets rotations/locations. You can read from the 'old' threads that this causes unwanted behavior of the physics engine.
I have heard you can make it so the camera's rotation does not affect the cube's rotation, or even better, the cube's rotation does not affect the camera. I never tried it though.
I think I'd actually be more interested in a Gears of War styled controller… any help is welcome.
Has anybody figured out how to suppress the up/down mouselook using NodeHandler or similar?? I've tried so many things but have never succeeded.
Is there a way to define an Axis (the character's y-axis), then have the camera swing around that axis, while having the character always face away from the camera? However, I still need to ONLY swing on the y axis and never have it move up/down. Is there some way I can utilize the lookAt or getRotation methods for this?
I am close–if I use the following code:
charNode.lookAt(cam.getDirection());
During update, the character turns on it's axis but the up/down mouselook doesn't affect it. Now all I need to do is to get the keys working from the NodeHandler and I'm set...