Key debouncing and pause modes

For the curious I have spent the past week (off and on) making a pause button work. Yes, after a week of coding I have managed to allow the player to press the ‘P’ key and see a little “The game is paused, press P to unpause, Q to Quit” box appear on the screen. Not only that, but the player can then actually press ‘P’ again and go back to watching a black screen with a red triangle on it (the “game”), or press ‘Q’ and go back to the main menu.

Which makes it sound like I’ve done bugger all really. And that’s the problem with measuring progress by things you create and can actually demonstrate to other people. You see, what I really achieved this week is

  • An understanding of how to composite different alpha blended bitmaps on the display
  • How to debounce keyboard input (so that pressing the ‘P’ key means “the user pressed it once, not twice and holding it down counts as one press, even if they’ve not let it go”)
  • How to bundle all this away in a neat and tidy class
  • An actual real use for C++ namespaces

My game engine thing now has a proper, clean system for starting up, showing a main menu, running the game itself and then allowing the user to pause and quit. So now things won’t explode in a shower of alertboxes when I want to exit the running code.

Keyboard debouncing in Allegro is an interesting little puzzle. Here’s the problem…

Allegro has a global “keys” array that contains the curret state of the keyboard. If a key is pressed at the time of checking, its corresponding entry is marked as being true. If the key isn’t pressed, it’s marked as false.

“Pressed” means the key is held down. It doesn’t mean it has been held down and then released.

So I have an array that shows me which keys are currently being held down. I do not have a convenient “has the user recently pressed the ‘P’ key” function. The concept of a “key press” does not exist in the Allegro toolkit (well, it does, but not in a way that’s useful) At first this doesn’t seem like much of a problem…

If the left_key is held down then move the ship to the left. If the right_key is held down, move the ship to the right.

That works fine for things where holding down a key is desired or not important. However, popping up a pause box when the user presses ‘P’ and then making it go away when they press ‘P’ again requires a bit more thought. You can’t say

If the user holds down ‘P’ then show the pause screen and set the state to be ‘paused’.

if the state is paused and the user holds down the ‘P’ key then set the state to ‘game’.

Why? Because unless you very quickly stab the key quicker than the code can go from the first state to the second state you’ll do nothing more than flash the pause screen for one frame. Why? Because people are slow. We press keys and hold them down for relatively long periods of time compared to how quickly the game’s loop runs. The code is faster than our human reactions, which is important if you think about it – the screen has to update at least 25 times a second to appear as fluid motion. And I don’t know about you, but I don’t habitually tap my keys that quickly.

So we need some sort of latching system to say “if the key is held down, ignore it until it is not held down”. This logic is not that complicated, but somewhat hard to work out the first time.

// This copes with the key being pressed down before the code even runs
if (key_held[key_p]) then p_is_held = true;

// imagine this is the main loop
while (not_quit) {
    // has the key been held down, and the key currently not marked as held down?
    // imagine this as a rising-edge trigger, if your brain works that way
    if (key_held[key_p] and p_is_held = not true) {
        p_is_held = true;    // mark this key as being held down
        can_pause = true;  // and turn on the ability to pause
    }
    // is the key not held down?
    if (key_held[key_p] = not true)
        p_is_held = false;    // mark the key as not being held down, but do nothing else

    // Note how we use the "can pause" flag to see if the pause code should run, not the key itself
    // the key presses and the logic being run when the key is pressed have been separated from each other
    if (can_pause) {
        do the pause stuff here
        can_pause = false;    // reset this so it can be re-triggered
    }

The next thing I’ll be doing is getting some sprites loaded in and showing them on the screen. After that, maybe something else interesting like LUA integration, or some sort of virtual filesystem so that game data can be provided as a single data file in exactly the same way Doom has WAD files, and Quake has PAK files.

I’m making a lot of work for myself when I could just get on with making games, but I’m also learning useful things that aren’t specific to any sort of game or application. It’s all reusable code and algorithms.

Top tip: Make sure you tell Allegro to use 16, 24 or 32 bit colour otherwise it defaults to 8 and any form of alpha blending makes your code crash!

About the Author