Search code examples
javaloops3drenderlwjgl

Java - recieving input in loop


I use LWJGL for 3d graphics.

The thing i want to do is to change render type from "GL_TRIANGLES" to "GL_LINES" by pressing a specified key (For example - F1). Because of a high framerate normal

if(Keyboard.isKeyDown(key))
        {
            //Action
        }

would switch on and off up to 200 times during normal button press. Overall, its interesting to me, how this problem is usually solved, and whats the best way to deal with it.

So the thing i came up with is (Probably, very ineffective):

//Render class init
Key F1 = new Key(Keyboard.KEY_F1);

//Render method
renderMode = F1.ifPressed(delta);
if(renderMode)
{
    //GL_LINES render
}
else
{
    //GL_TRIANGLES render
}

//Key class
public class Key 
{
    int DELAY_TIME = 20;
    int delay = 0;
    int key;
    boolean isActive = false;
    boolean  state = false;

public Key(int key)
{
    this.key = key;
}

public boolean ifPressed(int delta)
{
    if(!isActive)
    {
        if(Keyboard.isKeyDown(key))
        {
            isActive = true;
            state = !state;
            return state;
        }
    }
    else if(delay <= DELAY_TIME * delta)
    {
        delay++;
    }
    else if(delay > DELAY_TIME)
    {
        delay = 0;
        isActive = false;
    }
    return state;

Solution

  • One general solution is to have a list of currently active actions / pressed keys. When an input event PRESSED is fired (this is typically done by the framework / OS) for some key, you check if that key is in the list.

    if (list.contains(key)) {
        // not first time, so fire held
        onKeyHeld(key);
    }
    else {
        list.add(key);
        onKeyPressed(key);
    }
    

    When an input event RELEASED is fired, you do the following:

    list.remove(key);
    onKeyReleased(key);
    

    Mouse events are done in a similar way.

    Better still you can replace those methods with some UserAction class, so that it can be bound to keys / mouse events. The code would change to something like:

    bind(Key.SPACE, new UserAction("Jump") {
        public void onActionStart() {} // on key pressed
        public void onAction() {}      // on key held
        public void onActionEnd() {}   // on key released
    });
    

    I have used this solution in a game library and therefore can confirm that it works.