Problem waiting for a key to be pressed

Started by
4 comments, last by Napox 13 years, 2 months ago
Hi, as I said in another post, I'm making a simple Pong clone, but this time I'm having some problems with the event handling thing. The idea is that I want the game to ask the players if they want to play again or not, if they answer yes, the game restarts the ball and paddle's position and the player's points, if the answer is no the game is closed. To do that there's a method waiting for the key Y or N to return true or false, but if after a while the player don't press Y or N the game keeps running and if you try to move the mouse or one of the paddles the game freezes. I want the game to wait until one of the keys is pressed.

The main.cpp:



int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO);

TTF_Init();

Game *myGame = new Game();

SDL_Event event;

bool quit = false;
bool restart = false;

myGame->startTimer();

while (!quit)
{
while (SDL_PollEvent(&event))
{
if(restart)
{
if(myGame->playAgain(event))
{
myGame->restartGame();
restart = false;
}

else
{
quit = true;
}
}

else
{
myGame->handleEvents(event);
}

if (event.type == SDL_QUIT)
{
quit = true;
}
}


myGame->moveInstruments();

myGame->checkCollisions();

myGame->updateCounter();

myGame->drawScreen();

if (!myGame->anyWinner())
{
myGame->showInstruments();
}

else
{
restart = true;

myGame->showWinner();

myGame->askToPlayAgain();
}

if( myGame->updateScreen() == -1 )
{
return 1;
}

}

delete myGame;

myGame = NULL;

SDL_Quit();

return 0;
}




The playAgain() method:



bool Game::playAgain(SDL_Event event)
{
bool keyPressed = false;

while(!keyPressed)
{
if (event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_y:

return true;

case SDLK_n:

return false;

default:;
}
}
}
return false;
}







I also tried to modify a little the main.cpp adding the following after the while (SDL_PollEvent(&event)) loop:



if(!quit)
{
myGame->moveInstruments();

myGame->checkCollisions();

myGame->updateCounter();

myGame->drawScreen();

if (!myGame->anyWinner())
{
myGame->showInstruments();
}

else
{
restart = true;

myGame->showWinner();
//The following method applies a surface from ttf asking if the players want to play again
myGame->askToPlayAgain();
}

if( myGame->updateScreen() == -1 )
{
return 1;
}

}

}

delete myGame;

myGame = NULL;

SDL_Quit();


return 0;






Thanks in advance.
Advertisement
Just at first glance (I may be missing something) your playAgain() method looks like a trap? Here's the outline, as I read it:

while (true) loop;
- keyPressed is set to false, and the while condition is not-false...which is true. keyPressed is never changed, so it's misleading to use it at all. You want to loop until the player says Y or N, so perhaps you mean, literally while(true) ?

Your'e passing in event and then getting trapped in that infinite loop. event is never changed while it's in the loop, so if the event was not a keypress, you're trapped within forever. If you're going to loop inside that method, you'll want to constantly poll for events, or if it's a callback don't put an infinite loop in there.

If the event IS a keypress, and it's either a 'y' or an 'n' it gets handled and returns; if it's neither of these things (a space bar, a control key) then again you're trapped in your infinite loop.

See what I mean? This method, at least, needs revisiting. =)

Just at first glance (I may be missing something) your playAgain() method looks like a trap? Here's the outline, as I read it:

while (true) loop;
- keyPressed is set to false, and the while condition is not-false...which is true. keyPressed is never changed, so it's misleading to use it at all. You want to loop until the player says Y or N, so perhaps you mean, literally while(true) ?

Your'e passing in event and then getting trapped in that infinite loop. event is never changed while it's in the loop, so if the event was not a keypress, you're trapped within forever. If you're going to loop inside that method, you'll want to constantly poll for events, or if it's a callback don't put an infinite loop in there.

If the event IS a keypress, and it's either a 'y' or an 'n' it gets handled and returns; if it's neither of these things (a space bar, a control key) then again you're trapped in your infinite loop.

See what I mean? This method, at least, needs revisiting. =)

Thanks, you're totally right. I modified it a little so the method could polls for events, adding a while(SDL_PollEvents(&event)) loop, the freeze is fixed, now the game is closed (quit = true), but it still continues without waiting for the key indefinitely.




Unless you are very sure of what you are doing, I would recommend you not poll for events in multiple places. For example, you will probably want a bunch of common handlers, such as SDL_QUIT and possibly the escape key, and hotkeys for toggling fullscreen, etc. Polling in multiple places can make it hard to ensure that this kind of code will always work. Instead, conditionally execute the game logic depending on whether you are waiting. You might consider a state machine approach if there are more special cases.
I admit I'm with rip-off on this. Polling for events right there in that method is a quick fix, and for a small project (or a very early project, which I had guessed this is?) it's not terrible...but it's definitely not something you want to get in the habit of either.

Try instead moving the polling outside to the main-control loop and having that loop operate the game in it's normal state and the wait-for-yes-or-no question in a special state. You can also have the menu be a state, the credits, whatever, all off of the same main control loop. Loop gets to big? Move all of the non-looping parts out to helper methods (such as your playAgain method). In short, put any loops that are meant to wait for something to happen in those branches; stick to the main loop.

You already have the basics for this. =) Just set and check for state before responding to the event you trap at the start of your main loop. Depending on what state you're in, that input can be handled as in-game controls, menu controls, whatever.

Unless you are very sure of what you are doing, I would recommend you not poll for events in multiple places. For example, you will probably want a bunch of common handlers, such as SDL_QUIT and possibly the escape key, and hotkeys for toggling fullscreen, etc. Polling in multiple places can make it hard to ensure that this kind of code will always work. Instead, conditionally execute the game logic depending on whether you are waiting. You might consider a state machine approach if there are more special cases.




I admit I'm with rip-off on this. Polling for events right there in that method is a quick fix, and for a small project (or a very early project, which I had guessed this is?) it's not terrible...but it's definitely not something you want to get in the habit of either.

Try instead moving the polling outside to the main-control loop and having that loop operate the game in it's normal state and the wait-for-yes-or-no question in a special state. You can also have the menu be a state, the credits, whatever, all off of the same main control loop. Loop gets to big? Move all of the non-looping parts out to helper methods (such as your playAgain method). In short, put any loops that are meant to wait for something to happen in those branches; stick to the main loop.

You already have the basics for this. =) Just set and check for state before responding to the event you trap at the start of your main loop. Depending on what state you're in, that input can be handled as in-game controls, menu controls, whatever.

Thanks, both of you. I'll read about state machines to see what I can do about that.


This topic is closed to new replies.

Advertisement