ActionTriggers, strange behavior

Hello,



I am pretty fresh to JmonkeEngine and I've got some questions about the Input Handling. Somehow I cannot spot any consistency in the behavior of the ActionTriggers. So, I don't know if I use it in a wrong way, or maybe this is the expected behavior, but I think it would need some more decomentation about all these special cases …



I see the same problems on the SimpleGame and also on with a StandardGame.

I am using the latest SVN Revision 4483 from http://jmonkeyengine.googlecode.com/svn/trunk/



Below is the code I've used to test. The actual outcome of the Test is commented within the code. To reproduce just start it, choose JOGL/LWJGL and press the buttons 1 to 4.



I tested it on two systems and get the same strange behavior on both machines.



The questions I have therefore are:


  • Do I use the Triggers somehow wrong ?

    Or is it really not consistent between the JOGL/LWJGL ? -> but then my question is, isn't it the target of jmonkey to hide these subtle differences ?


  • What I need is the CommandTrigger behavior with the possibility to query the triggerPressed(). As you can see in the listed outcome below, this option is not available of all the combinations I tried.





    Thanks for any answers,

    maxx_981



import com.jme.app.SimpleGame;
import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.KeyBindingManager;
import com.jme.input.action.InputActionEvent;
import com.jme.input.action.KeyInputAction;

import java.util.logging.Logger;
/*
 * Copyright (c) 2003-2009 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.
 */

/**
 * maxx_981, TestInputHandlerTimings
 *


 * Tested on:
 * - Intel Core Due E8200, 32-bit Vista
 * - Genuine Intel CPU T2500, 32-bit XP
 * -> same behavior
 * <p/>
 * Don't think the graphics setup is of any importance here ...
 */
public class TestInputHandlerTimings extends SimpleGame
{
    private static long lastTime;
    private static long lastTimeKeyS;
    private boolean triggerPressed = false;

    private InputHandler input1;

    protected void simpleInitGame()
    {
        input1 = new InputHandler();

        // on JOGL:
        //
        // KEY_1 (Based on KeyTrigger)
        // if 'boolean allowRepeats' is set to true, there will be an endless triggering of the Key, as soon as it
        // is held down for more than like 1-2 seconds.
        // Also, the tiggerPressed value is not available, its just alwas true (ie. not even default false) ?
        //   -> Unexpected Behavior.
        //
        // KEY_2 (Based on KeyTrigger)
        // if 'boolean allowRepeats' is set to false, the trigger repeats, but is very slow, and it has an initial
        // delay, see outputs ... for example the tiggering. The rhythm is about 30ms and at the beginning there are
        // two 500ms interrupts, after the first outputed high number, which is just the time since the last key press.
        // Here the triggerPressed value is correct. But overall                                  
        //   -> Unexpected behavior.
        //
        // KEY_3 (Based on CommandTrigger and KeyBindingManager)
        // if 'boolean allowRepeats' is set to true, the trigger repeats very fast, no delay. No triggerPressed
        // available.  
        //   -> Expected Behavior. But no trigger info ...
        //
        // KEY_4 (Based on CommandTrigger and KeyBindingManager)
        // if 'boolean allowRepeats' is set to false, the trigger is activate once. No triggerPressed available.    
        //   -> Expected Behavior. But no trigger info ...

        // on LWGL
        //
        // KEY_1  (Based on KeyTrigger)
        // if 'boolean allowRepeats' is set to true, trigger repeats very fast, no delay (also no infinite looping).
        // But the tiggerPressed value is not available, its just alwas true (ie. not even default false) ?                  
        //    -> Unexpected Behavior.
        //
        // KEY_2  (Based on KeyTrigger)
        // if 'boolean allowRepeats' is set to false, the trigger is activate once, and the triggerPressed info is  
        // available
        //  -> Expected Behavior.  But there is no info about which button which was released.
        //
        //
        // KEY_3 (Based on CommandTrigger and KeyBindingManager)
        // if 'boolean allowRepeats' is set to true, the trigger repeats very fast, no delay. No triggerPressed
        // available.    
        //   -> Expected Behavior. But no trigger info ...
        //
        // KEY_4 (Based on CommandTrigger and KeyBindingManager)
        // if 'boolean allowRepeats' is set to false, the trigger is activate once. No triggerPressed available.      
        //   -> Expected Behavior. But no trigger info ...


        // setting up KEY_1/KEY_2
        input1.addAction(new MyKeyInputActionKeyTrigger(), InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_1, InputHandler.AXIS_NONE, true);
        input1.addAction(new MyKeyInputActionKeyTrigger(), InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_2, InputHandler.AXIS_NONE, false);


        // setting up KEY_3/KEY_4
        {
            KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
            keyboard.set("press3", KeyInput.KEY_3);
            MyKeyInputActionCommand pressS = new MyKeyInputActionCommand();
            input1.addAction(pressS, "press3", true);
        }
        {
            KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
            keyboard.set("press4", KeyInput.KEY_4);
            MyKeyInputActionCommand pressS = new MyKeyInputActionCommand();
            input1.addAction(pressS, "press4", false);
        }
    }

    @Override
    protected void simpleUpdate()
    {
        input1.update(tpf);
    }

    public static void main(String[] args)
    {
        TestInputHandlerTimings app = new TestInputHandlerTimings();

        app.setConfigShowMode(ConfigShowMode.AlwaysShow);
        app.start();
    }


    /**
     * A KeyInputAction, evt values should be present
     */
    public class MyKeyInputActionKeyTrigger extends KeyInputAction
    {
        public MyKeyInputActionKeyTrigger()
        {
        }

        public void performAction(InputActionEvent evt)
        {
            triggerPressed = evt.getTriggerPressed();

            long timeDiff = (System.currentTimeMillis() - lastTime);
            if (timeDiff < 100000000)
            {
                System.out.println(evt.getTriggerCharacter() + " Pressed: millis since last update: " + timeDiff + " triggerPressed: " + triggerPressed);
            }
            else
            {
                System.out.println(evt.getTriggerCharacter() + " Pressed for the first time at: " + System.currentTimeMillis() + " triggerPressed: " + triggerPressed);
            }

            lastTime = System.currentTimeMillis();
        }
    }

    /**
     * A KeyInputAction, no evt values expected
     */
    public class MyKeyInputActionCommand extends KeyInputAction
    {
        public MyKeyInputActionCommand()
        {
        }

        public void performAction(InputActionEvent evt)
        {
            long timeDiff = (System.currentTimeMillis() - lastTimeKeyS);
            if (timeDiff < 100000000)
            {
                System.out.println("3 or 4 Pressed: millis since last update: " + timeDiff);
            }
            else
            {
                System.out.println("3 or 4 Pressed for the first time: " + System.currentTimeMillis());
            }

            lastTimeKeyS = System.currentTimeMillis();
        }
    }

}

The jogl implementation still has a few problems, but its being worked on recently by a few people.


Hy Core-Dump,



but it seems to me that LWJGL also got problems.

For example the evt information is not available when setting allowRepeats to true.



Say, you wanted to use a KeyTrigger-ActionTrigger with repeats and use the evt information,

so we change the FlagRush-Tutorial Handler from lession 9 to the code below. This will give us

a behavior which is expected, but no trigger information ?



Thank you

maxx_981



/*
 * Copyright (c) 2003-2009 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.
 */

/**
* maxx_981: adjustments for testing the KeyTrigger (on LWJGL)
*
**/

package jmetest.flagrushtut.lesson9;

import jmetest.flagrushtut.lesson9.actions.DriftAction;
import jmetest.flagrushtut.lesson9.actions.ForwardAndBackwardAction;
import jmetest.flagrushtut.lesson9.actions.VehicleRotateAction;

import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;

/**
 * Input Handler for the Flag Rush game. This controls a supplied spatial
 * allowing us to move it forward, backward and rotate it left and right.
 * @author Mark Powell
 *
 */
public class FlagRushHandler extends InputHandler {
    //the vehicle we are going to control
    private Vehicle vehicle;
    //the default action
    private DriftAction drift;
    
    public void update(float time) {
        if ( !isEnabled() ) return;

        super.update(time);
        //we always want to allow friction to control the drift
        drift.performAction(event);
        vehicle.update(time);
    }
    
    /**
     * Supply the node to control and the api that will handle input creation.
     * @param vehicle the node we wish to move
     * @param api the library that will handle creation of the input.
     */
    public FlagRushHandler(Vehicle vehicle, String api) {
        this.vehicle = vehicle;
        setKeyBindings(api);
        setActions(vehicle);

    }

    /**
     * creates the keyboard object, allowing us to obtain the values of a keyboard as keys are
     * pressed. It then sets the actions to be triggered based on if certain keys are pressed (WSAD).
     * @param api the library that will handle creation of the input.
     */
    private void setKeyBindings(String api) {
//        We do not use the KeyBindingManager ...
//
//        KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
//
//        keyboard.set("forward", KeyInput.KEY_W);
//        keyboard.set("backward", KeyInput.KEY_S);
//        keyboard.set("turnRight", KeyInput.KEY_D);
//        keyboard.set("turnLeft", KeyInput.KEY_A);
    }

    /**
     * assigns action classes to triggers. These actions handle moving the node forward, backward and
     * rotating it. It also creates an action for drifting that is not assigned to key trigger, this
     * action will occur each frame.
     * @param node the node to control.
     */
    private void setActions(Vehicle node) {
//        ForwardAndBackwardAction forward = new ForwardAndBackwardAction(node, ForwardAndBackwardAction.FORWARD);
//        addAction(forward, "forward", true);
//        ForwardAndBackwardAction backward = new ForwardAndBackwardAction(node, ForwardAndBackwardAction.BACKWARD);
//        addAction(backward, "backward", true);
//        VehicleRotateAction rotateLeft = new VehicleRotateAction(node, VehicleRotateAction.LEFT);
//        addAction(rotateLeft, "turnLeft", true);
//        VehicleRotateAction rotateRight = new VehicleRotateAction(node, VehicleRotateAction.RIGHT);
//        addAction(rotateRight, "turnRight", true);

   // we use KeyTriggers instead ....
        ForwardAndBackwardAction forward = new ForwardAndBackwardAction(node, ForwardAndBackwardAction.FORWARD);
        addAction(forward, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_W, InputHandler.AXIS_NONE, true);

        ForwardAndBackwardAction backward = new ForwardAndBackwardAction(node, ForwardAndBackwardAction.BACKWARD);
        addAction(backward, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_S, InputHandler.AXIS_NONE, true);

        VehicleRotateAction rotateLeft = new VehicleRotateAction(node,VehicleRotateAction.LEFT);
        addAction(rotateLeft, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_A, InputHandler.AXIS_NONE, true);

        VehicleRotateAction rotateRight = new VehicleRotateAction(node, VehicleRotateAction.RIGHT);
        addAction(rotateRight, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_D, InputHandler.AXIS_NONE, true);




        //not triggered by keyboard
        drift = new DriftAction(node);
    }
}