Handling player input
Posted September 10th, 2009 by Bert HekmanTo kill as many birds as you can, with one stone. That was my goal when I created the GameInput class. I wanted it to handle the keyboard and joystick input for one player. Here’s how it works.
Keyboard keys, joystick buttons and axis movements should generate actions. And with actions I mean stuff like: move left, jump, fire and start.
Let’s say we’ve defined the following actions: ACT_LEFT, ACT_RIGHT, ACT_UP, ACT_DOWN, ACT_FIRE and ACT_START. The next thing we need to do is instantiate the GameInput class and enable the keyboard and joystick. And after that we need to bind keys, joystick buttons, axes or hat presses to certain actions:
GameInput * input = new GameInput(); input->enable_keyboard(true); input->enable_joystick(true); input->open_joystick(0); // Open the first available joystick input->bind_key(SDLK_LEFT, ACT_LEFT); // Bind keyboard left to action left input->bind_joyaxis(0, false, ACT_LEFT); // Bind the first axis in the negative // direction to action left input->bind_key(SDLK_RIGHT, ACT_RIGHT); // Bind keyboard right to action right input->bind_joyaxis(0, true, ACT_RIGHT); // Bind the first axis in the positive // direction to action right input->bind_key(SDLK_SPACE, ACT_FIRE); // Bind spacebar to action fire input->bind_joybutton(1, ACT_FIRE); // Bind the joystick button 2 to action fire // ...and so on...
Now we’ve set up the input class, but still it doesn’t work when we do not pass the events to it. We need to pass every input event SDL generates to the input class, to check if any action is triggered by the player. This may look something like this:
SDL_Event event; while(is_running) { while(SDL_PollEvent(&event) { input->handle_event(&event); } // ... do game logic, draw the game // flip the frame buffer, handle fps rate, etc }
And that’s it, really. Now you can use the following function to check if the player has triggered some action:
if(input->is_pressed(ACT_FIRE)) do_fire();
While this may work great for the gameplay, we also want to use the same input handler for the menu’s. And since games run at a fast rate (Smash Battle runs at 60 fps), pressing the down-button would cause the menu cursor to move down 60 items per second, which is way too fast. That is why I’ve added the function to set a delay:
input->set_delay(); // Sets the delay, with the default parameters input->set_delay(30, 15); // Sets the delay, with different parameters input->unset_delay(); // Unsets the delay, is the same as set_delay(0, 0)
The delay exists out of two parameters: delay and interval. When you press a button, it immediately acts. Then it waits x frames, defined by the delay parameter, before it acts again. After that it always waits with an interval of y frames, which is defined by the second parameter: interval, until you release the button. The default setting of delay=18 and interval=6 works fine and feels natural. It works the same way as pressing and holding a key on your keyboard, when you’re typing text.
Another problem is that we don’t want input which was destined to act with a previous menu screen or game session to act in a new menu or game session. This can be prevented with the reset-function:
input->reset();
This resets all actions to false, as if nothing was pressed. So you’ll need to repress the button, before it acts, preventing unwanted actions in a following screen or game session.
By now, I’ve told you everything there is to my GameInput class. If you’d like to know how it works in Smash Battle, you can check it out on my WebSVN.
Smash Battle trunk (WebSVN)
Some relevant files: GameInput.cpp GameInput.h Gameplay.cpp Player.cpp (check out the move-function)
while(SDL_PollEvent(&event)) {
One Response to “Handling player input”
September 25th, 2009 at 12:26
[…] Battle: Handling player input About two weeks ago, I wrote an article on how the player input is handled in Smash Battle. It basically tells what the GameInput class does and how to use it. It might be useful if you're […]
Leave a Reply