Newer code examples for mouse control

I'm new to jME, but an old veteran of J3D. I've looked far and wide for some updated example code of how to control a mouse. What I'm trying to do is create a "Behavior" that acts like the OrbitBehavior in Java3D. At this point, I'm thoroughly confused about where to begin…



Most of the examples I've found have deprecated methods.



Any help would be appreciated!

Have you seen this one in the wiki. You can also take a look at TestInputHandler.

dig your way down through the source of thirdpersonhandler etc

I can't recommend what MrCoder suggested as ThirdPersonHandler and alot of other code still uses old-style action binding. Prefer to have a look into AbsoluteMouse, which displays a mouse cursor and can be configured to react on joystick or synthetic input (e.g. axis from key input)…

Thanks Irrisor…



The wiki link coupled with the javadocs are starting to sink in.



So, the relationship/process invloves:


  1. Setting up a provider for mouse movements/buttons. This is done through an apparent static call to the MouseInput class.


  2. Create a specific input handler that receives callbacks from the provider in its performAction method. The provider passes an InputActionEvent back to the InputHandler.


  3. Add the new input handler to 'input', as a 'listener' for events.



    Is this correct?



    Why, in all of the examples, is the var 'input' always used? Such as 'input.addAction(…)'? Even though input is part of the parent class? In other words, in the examples I've seen, input is called sort of like a global variable from its parent class–is this a programming paradigm?



    Thanks again.

Especially 2. and 3. don't sound correct. Especially you seldomly would ever write an InputHandler but only subclasses of InputAction.

I'll try to outline in a similar way:



a) write subclasses of InputAction to define what should happen on various input events, e.g. mouse move -> translate cam, button press -> cam reset, using only the data given in the InputEvent or action ctor

b) set up one or more InputHandler (probably in a hierarchy) that get updated every frame and could be enabled/disabled to toggle functionality groups

c) bind actions to actual controls (possibly via a configuration file/gui) to have action from a) triggered by e.g. mouse axis or buttons respectively



SimpleGame creates and updates an InputHandler for it's subclasses and stores it in a protected field named 'input' for simplicity. In a finished game you will most probably have more than just one InputHandler.

Thanks again, irrisor. This is a big help.



Now, time to write some code…

Hey if you want some help I saw this post and wanted to try something simple.



Basically use the existing NodeHandler mouse/keyboard handler, but trick it out by passing in 2 nodes (targetNode, OrbitingNode), and creating an auxiliary node that will hold the orbitingNode at a radius specified, and then use the normal NodeMouseLook to rotate this auxiliary node given the mouse inputs. Also I turned off the MouseLook lockAxis because when rotating around a node you can be free to rotate in whichever orientation makes sense (although if you want to change it just uncomment those lines).



The important method is the setupOrbitNode of the NodeOrbitHandler:



    private Node setupOrbitNode(Spatial targetNode, Spatial orbitingNode, float radius) {
        Node n = new Node ("OrbitNode");
        n.setLocalTranslation(targetNode.getWorldTranslation());
        //Position the orbiting node out in orbit given the radius
        orbitingNode.setLocalTranslation(new Vector3f(0,0,-1).mult(radius));
        n.attachChild(orbitingNode);
        return n;
    }



The major limitation of this implementation is that you need to retrieve that auxiliary node and attach it to your scene graph, a better implementation would be to on every update that the orbiting node is moving to position it at a rotated normal direction vector * radius away from the target node (not sure how to cleanly and easily do this with Handlers/Actions, I also didn't spend to much time on it).


Here's the Test class, followed by the NodeOrbitHandler, so you can try them out, the test is a sphere being orbited around by a CameraNode, and a box in the background so that you can see the camera is actually orbiting around the sphere, and the sphere isn't the one rotating.

HelloNodeController.java


/*
 * Copyright (c) 2003-2006 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jmetest.TutorialGuide;

import com.jme.app.AbstractGame;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.input.NodeHandler;
import com.jme.input.NodeOrbitHandler;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.LightState;

public class HelloNodeController extends SimpleGame {
    public static void main(String[] args) {
        HelloNodeController app = new HelloNodeController();
        app.setDialogBehaviour(AbstractGame.ALWAYS_SHOW_PROPS_DIALOG);
        app.start();
    }

    protected void simpleInitGame() {
    
       
        Box b = new Box("TestBox", new Vector3f(0, 0, 0), 2, 2, 2);
        b.setLocalTranslation(new Vector3f(0,20,0));
        b.setRandomColors();

        Sphere s=new Sphere("My sphere",10,10,1f);
        // Do bounds for the sphere, but we'll use a BoundingBox this time
        s.setModelBound(new BoundingBox());
        s.updateModelBound();
        // Give the sphere random colors
        s.setRandomColors();
       
        /**
         * Set the input to control the CameraNode to orbit around the sphere
         * using the mouse.
         */
        CameraNode cameraNode = new CameraNode( "Camera Node", cam );
        cameraNode.updateWorldData( 0 );           
       
        //The camera will orbit (50 units away) around the sphere.
        NodeOrbitHandler nodeOrbitHandler = new NodeOrbitHandler(s, cameraNode, 50f, .5f, 20f );
        Spatial orbitingNode = nodeOrbitHandler.getOrbitingNode();
        input = nodeOrbitHandler;
       
        // Remove  lighting for rootNode so that it will use our basic colors.
        rootNode.setLightCombineMode(LightState.OFF);
       
        rootNode.attachChild(s);
        rootNode.attachChild(b);
        rootNode.attachChild(orbitingNode);
    }
}




NodeOrbitHandler.java


/*
 * Copyright (c) 2003-2006 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jme.input;

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.input.action.NodeMouseLook;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
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 NodeOrbitHandler extends InputHandler {

    //This is the node that the orbitingNode will rotate around
    private Spatial target;
   
    //The node that will orbit the targetNode
    private Spatial orbiter;
   
    /**
     * 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 NodeOrbitHandler(Spatial targetNode, Spatial orbitingNode) { //todo: remove parameter api
        this(targetNode,orbitingNode, 0.5f, 1, 5.0f);
    }

    /**
     * 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 NodeOrbitHandler(Spatial targetNode, Spatial orbitingNode, float keySpeed, float mouseSpeed, float radius) {
        Node node = setupOrbitNode(targetNode, orbitingNode, radius);
       
        setUpMouse(node, mouseSpeed );
        setActions(node, keySpeed, mouseSpeed );
       
        this.target = targetNode;
        this.orbiter = node;
    }

    private Node setupOrbitNode(Spatial targetNode, Spatial orbitingNode, float radius) {
        Node n = new Node ("OrbitNode");
        n.setLocalTranslation(targetNode.getWorldTranslation());
        //Position the orbiting node out in orbit given the radius
        orbitingNode.setLocalTranslation(new Vector3f(0,0,-1).mult(radius));
        n.attachChild(orbitingNode);
        return n;
    }

    /**
     *
     * <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 ) {
        RelativeMouse mouse = new RelativeMouse("Mouse Input");
        mouse.registerWithInputHandler( this );

        NodeMouseLook mouseLook = new NodeMouseLook(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 KeyNodeLookUpAction( node, turnSpeed ), "lookUp", true );
        addAction( new KeyNodeLookDownAction( node, turnSpeed ), "lookDown", 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 );
    }

    public Spatial getOrbitingNode() {
        // TODO Auto-generated method stub
        return this.orbiter;
    }
}