Best way to poll the keyboard

Started by gregorypierce, February 16, 2005, 20:53:39

Previous topic - Next topic

gregorypierce

Okay I'm trying to find out what they preferred way is to poll the keyboard. What I want to do is poll the Keyboard and have something happen (like fire a shot). What I'm trying to prevent, however, is firing off a number of shots equal to the framerate of the game.

Matzon

dont poll it..
simply just call Display.update as you always do, then iterate through all the events generated:
while (Keyboard.next()) {
    // ignore keyup
    if(!Keyboard.getEventKeyState()) {
      continue;
    }

    if (Keyboard.getEventKey() == Keyboard.KEY_RIGHT) {
      position.x += 1;
    }

    if (Keyboard.getEventKey() == Keyboard.KEY_LEFT) {
      position.x -= 1;
    }
}

gregorypierce

Gotcha. Elias mentioned the same thing after I posted this - was actually coming to take this message down :) Yeah I'm going to use buffered input and also make it a part of the modelling of things in the game. Weapons will have a 'recharge time' and when a shot is requested it will make sure that recharge time has been exceeded.

Thanks :)

Some of these little apps that I'm working on are so 'intro' that they are just running way to fast. The one I'm working on now is doing well over 200 fps - easily.

I was still doing it the old school way

       if (Keyboard.isKeyDown(Keyboard.KEY_LEFT))
        {
            setX(getX() - 0.3f);
        }
        else if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT))
        {
            setX(getX() + 0.3f);
        }
        else if (Keyboard.isKeyDown(Keyboard.KEY_UP))
        {
            setY(getY() - 0.5f);
        }
        else if (Keyboard.isKeyDown(Keyboard.KEY_DOWN))
        {
            setY(getY() + 0.5f);
        }
        else if (Keyboard.isKeyDown(Keyboard.KEY_SPACE))
        {
            shoot();
        }

gregorypierce

Yeah this is cool and it works fine. I had to alter the approach from a global perspective because doing it all buffered would lead me to another problem, needing to auto repeat keyevents for movement because I want you to move as long as you're holding the key down. Only after moving all of the keyboard reads into the buffered state did I notice the problem :)

So what I ended up doing (and this is for people who would follow behind trying to do the same thing) is split up the movement from the other events. Movement is registered through polling and shooting or other events are registered via the buffered mechanism. This worked flawlessly, though I'm not sure it was ever intended that one would use both input mechanisms simultaneously.

       if (Keyboard.isKeyDown(Keyboard.KEY_UP))
        {
            setY(getY() - 0.3f);
        }
        else if ( Keyboard.isKeyDown(Keyboard.KEY_DOWN))
        {
            setY(getY() + 0.3f);
        }
        else if ( Keyboard.isKeyDown(Keyboard.KEY_LEFT))
        {
            setX(getX() - 0.3f);
        }
        else if ( Keyboard.isKeyDown(Keyboard.KEY_RIGHT))
        {
            setX(getX() + 0.3f);
        }


        while ( Keyboard.next() )
        {
            // ignore keyup
            if(!Keyboard.getEventKeyState())
            {
                continue;
            }


            if ( Keyboard.getEventKey() == Keyboard.KEY_SPACE )
            {
                shoot();
            }
        }

Matzon

Well I hope that its meant to both at the same time, coz thats what I am doing too :)
And it makes sense. Buffered keys deals with "events", that is - has a key been pushed or released. While the isKeyDown deals with the current state of the keyboard.

You can however work around all this, by having somekind of timeout for an action. Which might be prefered.

aldacron

Quote from: "gregorypierce"Yeah this is cool and it works fine. I had to alter the approach from a global perspective because doing it all buffered would lead me to another problem, needing to auto repeat keyevents for movement because I want you to move as long as you're holding the key down. Only after moving all of the keyboard reads into the buffered state did I notice the problem :)

What about something like this:

while ( Keyboard.next() )
        {
            boolean keydown = Keyboard.getEventKeyState();
           
            switch(Keyboard.getEventKey())
            {
                case Keyboard.KEY_SPACE:
                   if(keydown)
                      shoot();
                   break;
             
                case Keyboard.KEY_UP:
                   setVelocityY(keydown ? baseVel : 0.0f);
                   break;

                case Keyboard.KEY_DOWN:
                   setVelocityY(keydown ? -baseVel : 0.0f); 
                   break;

                case Keyboard.KEY_LEFT:
                   setVelocityX(keyDown ? -baseVel : 0.0f);
                   break;

                case Keyboard.KEY_RIGHT:
                   setVelocityX(keyDown ? baseVel : 0.0f);
                   break;

                 default:
                    break;

            }
            if ( Keyboard.getEventKey() == Keyboard.KEY_SPACE )
            {
                shoot();
            }

            else if(Keyboard.getEventKey() == Keyboard.KEY_UP)
            {
             
            }
        }


Add velocityX and velocityY to x and y in your render method. It's always a good idea to keep position and velocity separate until the last minute.

gregorypierce

This particular example doesn't use velocity. Things just move so long as you're pressing the key.

What you are proposing would be good for things that gain/lose velocity over time by keyinput, but this isn't one of those cases. This is more in line with the traditional shooter model which isn't velocity based.

Teeth

I wrapped up the keyboard into a class (KeyboardHandler) of my own. The class uses a hash map of "KeyboardKey" objects. At any time, a user can add a key ID from Keyboard (e.g. Keyboard.KEY_LEFT) to the map, which is stored as one of these KeyboardKey objects, using the ID for the identifying key for the hash map. KeyboardHandler is update-aware, so it requires being updated in the game loop. Every update, the handler goes through all the KeyboardKeys in its map, and updates them. Each KeyboardKey knows whether it was down in the last update and whether it was down in this update. So at any time, you can ask the KeyboardHandler if a key has just been pressed (up last update, down this one) or if it's being held down (down both updates).

princec

Er, what's wrong is Keyboard.isKeyDown() for this sort of thing? The event handling stuff is purely for those writing OpenGL GUIs, and for the very specialist function of text edit controls at that...

Cas :)

Teeth

If it's not advised to use the event code for in-game antics, I can post the code for my keyboard handler, should anyone need it.

Matzon

princec, if using iskeydown you have to check against some time limit, else:
if(iskeydown()) {
 player.x += 1.0
}

will move you faster or slower depending on framerate which is rather uncool :)

Chman

Use time-based movements ;)

Chman

gregorypierce

Quote from: "princec"Er, what's wrong is Keyboard.isKeyDown() for this sort of thing? The event handling stuff is purely for those writing OpenGL GUIs, and for the very specialist function of text edit controls at that...

Cas :)

For me the problem is that "isKeyDown()" will result in an action each frame and if I'm running 200fps, that's a bad thing as the user will press space expecting one action and instead get 200 of them :)

Teeth

http://www.psychicteeth.co.uk/GameInput.rar

Sorry the package name isn't all com.dotted.up but there you go, feel free to use/expand/abstract it or whatever. It sounds like it'll do what you need it to.


Create a new KeyboardHandler, add keys to it with Map() after you created it and then poll them later. Update the KeyboardHandler once in each of your update loops. Job done.

gregorypierce

Nah, I'm good. I just needed to understand the semantics of the architecture. I've already got something that processes input and deals with key->game function mapping and the like. But thanks for the offer.

You might want to post it into the wiki though.