SDL: Two Event Loops? - c++

Take a look at this piece of code here:
void game::startLoop()
{
while(QUIT == false)
{
getRoomUpdate();
applySurface(-15, 280, zombie_lefthand, buffer);
applySurface(455, 280, zombie_righthand, buffer);
SDL_Flip(buffer);
while(SDL_PollEvent(&gameEvent))
{
if(gameEvent.type == SDL_QUIT)
{
QUIT = true;
}
}
while(SDL_WaitEvent(&keyEvent))
{
switch(keyEvent.type)
{
case SDL_KEYDOWN:
switch(keyEvent.key.keysym.sym)
{
//blahkeypress
}
}
}
}
}
I'm trying to figure out how to allow SDL_QUIT to work while we're waiting for a keypress. Is there a way to do this or do you guys have a better idea?
I'm a bit of a newbie so please be specific. :D

The name keyEvent is misleading. SDL_WaitEvent will wait for any sort of event, including QUIT.
SDL_Event event;
SDL_WaitEvent(&event);
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
/* cases for keyboard events, etc. */
}

Minimal changes:
You could add if (QUIT) break; after the inner while loop that sets QUIT.
Or, you could move the outer while loop to a separate function and add a return; after QUIT = true;.
Better changes:
Refactor your code similar to many examples available on the web (at sourceforge, or at molly rocket, or just google it).

Related

SDL 2.0.3 event loop doesn't work

I can't make SDL wait for a an event. When I try to the window just briefly flashes on my screen and then disappears, I don't get any errors or anything in my IDE, nothing in the build log either. I looked at lazyfoo and the SDL wiki, but no help. I'm using Code blocks and SDL 2.0.3 Here's what I have so far:
while(&event != NULL && !quit)
{
while(SDL_PollEvent(&event) > 0)
{
if(event.type == SDL_QUIT)
{
quit = true;
}
else
{
if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
currentSurface = keyPressSurfaces[KEY_PRESS_LEFT];
break;
case SDLK_UP:
currentSurface = keyPressSurfaces[KEY_PRESS_UP];
break;
case SDLK_RIGHT:
currentSurface = keyPressSurfaces[KEY_PRESS_RIGHT];
break;
case SDLK_DOWN:
currentSurface = keyPressSurfaces[KEY_PRESS_DOWN];
break;
default:
currentSurface = keyPressSurfaces[KEY_PRESS_DEFAULT];
break;
}
}
}
}
}
Any suggestions?
you are polling for an event SDL_PollEvent, if you want to wait for an event, you should use SDL_WaitEvent
First, is quit false before you enter this loop?
If there are no events to poll, I believe event is NULL, causing your program to exit the next time it sees while(&event != NULL && !quit). If there are no immediate events on startup, you might not ever make it into that loop. Edit: Whoops - thought event was a pointer:
The while (SDL_PollEvent(&event)) line will loop through until all pending events have been handled. The outter while (!quit) would then keep your program open even if there are no events to process at the moment.

The correct way to test 'SDL_PollEvent' in a 'while'

As the manual says, the function SDL_PollEvent "Returns 1 if there is a pending event or 0 if there are none available." , that's why we use the test SDL_PollEvent(&e)!=0 (where e is a SDL_Event).
But, what about use this test: !SDL_PollEvent(&e)? It should work,but apparently it cause some problem.
Here an example of code:
#include <SDL2/SDL.h>
#include <stdio.h>
int main(int argc, char* args[]){
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Hello",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100, SDL_WINDOW_SHOWN);
SDL_Event e;
int quit=0;
while(!quit){
//Here the test
while (!SDL_PollEvent(&e)){
if (e.type==SDL_QUIT)
quit=1;
else if ( e.type == SDL_KEYDOWN )
printf( "Hello\n" );
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
What this code should do is open a new window and print "Hello" in the console every time a key is pressed. This code works fine whit the test SDL_PollEvent(&e)!=0 but it doesn't read the SDL_KEYDOWN event when I use the test !SDL_PollEvent(&e) (but it DOES enter in the while and process the SDL_QUIT event without any problem).
Why this behaviour?
while (!SDL_PollEvent(&e))
needs to be:
while (SDL_PollEvent(&e))
if it should be the same as SDL_PollEvent(&e) != 0
because !SDL_PollEvent(&e) is the same as calling while(0)
(1 != 0) is true, but (!1) is false.
You probably should use SDL_WaitEvent instead anyway.
Addendum
One may think it's more clear to do something like this, since it ensures that user input is reacted upon. However, this is currently an OS dependent and possibly crazy CPU hog and will max out your CPU for this thread (on Windows). So you may think that you can just put a 1 second wait there, but then your window will become completely unresponsive or very laggy at best...
If you can live with a little CPU overhead for doing nothing, then you can compromise with using an 20-100 [ms] delay.
...
// Set the event handler...
...
bool isRunning = true;
while (isRunning) {
// Do the main thing here...
...
while(SDL_PollEvent(&windowEvent)) {
switch (windowEvent.type) {
case SDL_QUIT: isRunning = false;
case SDL_KEYDOWN: isRunning = false;
case SDL_MOUSEBUTTONDOWN: isRunning = false;
break;
}
SDL_Delay(100); // Wrong!
}
}
// End the program
So clearly this is not the correct way either. We need to use some other mechanism. Looking at the SDL repo, we find a long but very relevant discussion for the open issue:
SDL_WaitEvent causes high cpu usage
To Fix the issue
Make sure you put the delay in the outer loop, before the SDL_PollEvent().
// main loop
...
while(SDL_PollEvent(&windowEvent)) {
switch (windowEvent.type) {
case SDL_QUIT: isRunning = false;
case SDL_KEYDOWN: isRunning = false;
case SDL_MOUSEBUTTONDOWN: isRunning = false;
break;
}
}
SDL_Delay(100); // Right!
}

SDL event loop quitting?

I am making an RTS in C++ using SDL for graphics.
Every time I run the game, it crashes without errors or anything in the compiler debug window. It doesn't crash immediately or consistently, sometimes taking 10 seconds to crash and other times taking 2 minutes to crash.
When I played around with return values (at the end of the main function) it turned out it wasn't crashing, but rather quitting as the return values were consistent with what I changed it to.
The only theory that I have is that my poll event loop is glitching and telling the program to quit when it isn't supposed to.
Here is my event loop, contained within my game loop:
if( SDL_PollEvent( &event ) )
{
if( event.type == SDL_MOUSEMOTION )
{
mx = event.motion.x;
my = event.motion.y;
}
if( event.type == SDL_MOUSEBUTTONDOWN )
{
if( hut.getselected() && hut.getplacable() )
{
hut.place( map );
}
}
if( event.type == SDL_QUIT )
{
quit = true;
}
switch( event.key.keysym.sym )
{
case SDLK_ESCAPE: quit = true; break;
}
}
Is it possible that when the mouse moves or clicks, that it is confusing it for exiting? I don't think the ram is overloading either because it only displays what it needs to tile-wise.
Is it also possible that my compiler, VisualC++, is screwing up?
How about changing the switch at end of your snippet to:
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) {
quit = true;
}
Because in your code you check keysym for all events, so usually event is of wrong type when you test if it is escape, and you get "garbage" value for keysym, and sometimes it matches with ESC.
Actually might be good idea to test the event.type with switch:
switch(event.type) {
case SDL_MOUSEMOTION:
//....
break;
case SDK_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_ESCAPE:
quit = true;
break;
// cases for other keypresses
}
break;
// cases for other events
}

SDL Input gives "fake-Events" on Startup

I've got a little Problem with SDL:
When starting my Program (on Archlinux 64bit), SDL_event gives me some SDL_KEYDOWN events. The annoying thing with that is, that my Program Quits, when pressing ESCAPE.
Thats the Code:
void Input::update() {
[...]
while(SDL_PollEvent(event)) {
if (event != NULL) {
handleInput();
}
}
// SDL_PumpEvents(); Commented out, because of jrok's suggestion.
SDL_GetMouseState(&mousex, &mousey);
}
And:
void Input::handleInput() {
switch(event->type) {
case SDL_KEYDOWN:
setKey(event->key, true);
break;
case SDL_KEYUP:
setKey(event->key, false);
break;
case SDL_QUIT:
setQuit();
break;
default:
break;
}
}
setKey() sets an Element of an bool-Array to the given value (true/false).
Also, its not only the Escape-key. Often the other keys are pressed too.
Okey, sorry. SDL has not got any bugs, and the code, i have shown to you is right.
The problem was, that I didn't initialize my boolean Array. So there were Random values left...
That helped:
for (int i = 0; i < MAX_VAL; i++) {
keys[i] = false;
}

KeyRelease event never sent

I'm having a little problem catching a key released event to stop my character from walking in my game..
i'm trying to do this:
switch (xev.type)
{
case Expose:
{
XGetWindowAttributes(dpy, win, &gwa);
glViewport(0, 0, gwa.width, gwa.height);
}
break;
case KeyPress:
{
int key = XLookupKeysym(&xev.xkey, 0);
if (key == XK_Escape)
{
glXMakeCurrent(dpy, None, NULL);
glXDestroyContext(dpy, glc);
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);
running = false;
return 0;
}
else
{
input->setKey(key, true);
}
}
break;
case KeyRelease:
{
unsigned short is_retriggered = 0;
if (XEventsQueued(dpy, QueuedAfterReading))
{
XEvent nev;
XPeekEvent(dpy, &nev);
if (nev.type == KeyPress && nev.xkey.time
== xev.xkey.time && nev.xkey.keycode
== xev.xkey.keycode)
{
// delete retriggered KeyPress event
XNextEvent(dpy, &xev);
is_retriggered = 1;
}
}
if (!is_retriggered)
input->setKey(XLookupKeysym(&xev.xkey, 0), false);
}
break;
}
But I only get the re-triggered key release events, which I don't want. (even though a release/re-press would have the same result, but in the future it might give problems)
When i physically release the key, no event is caught.
oh, and input->setKey() basically sets a bool to true (or false) in a std::map, nothing special
This is a common gotcha. If you don't register for specific events (or all), you will not be notified.
All of us, doesn't matter the experience, will fall in this one day... :)
Some usefull links:
XSelectInput #Xorg
XSelectInput #tronche
Anatomy of the most basic Xlib program
Registering the KeyReleaseMask solved the problem.
XSelectInput(dis, win, KeyPressMask | KeyReleaseMask);