What to do with SDL2 events?

Started by
2 comments, last by reenigne 1 week, 6 days ago

edit: sorry connection issue I think the post got posted twice

I have some confusion or a misunderstanding using SDL2 events and getting data around to other areas in my code. There’s two ways that I’ve come to and I’m curious if one is better then the other or if perhaps there is a better way to go about this.

The first way I take the data and make my own event to be sent to listeners

while (SDL_PollEvent(&event)) {
    switch (event.type) {
    case SDL_KEYDOWN:
        events.fire<KeyEvent>(true, event.key.keysym.sym);
        break;
    case SDL_KEYDOWN:
        events.fire<KeyEvent>(true, event.key.keysym.sym);
        break;
    }

This seems to be the most logical way to do it, but I just can’t help but feel that jamming the data from an event into my own worst event system isn’t beneficial unless I’m overthinking/not seeing the bigger picture. Perhaps the soltuion is instead of trying to make my own event system I can create a SDLEventHandler and then stuff can handle events that way.

The second way I believe is just delegating the work to something else

while (SDL_PollEvent(&event)) {
    switch (event.type) {
    case SDL_QUIT:
        gameDetails.requestExit(); // Would set some bool to true which the main loop would check via gameDetails.shouldExit()
        break;
   }
Advertisement

And the third way is to change your event system to accept and transport SDL2 events. Basically same as the first way, but using SDL2 event structure instead of your own.

All ways work, and are therefore ok 🙂

They differ somewhat in other properties, Passing events through is useful if the systems that need them are not always the same or there are many receivers. My third way is cheaper to create then the first way, but it ties the event system hard to the SDL2 events. That gets tricky if you ever want to a different library at the bottom. First way can also easier accommodate other events than the set that SDL2 provides.

The second way works nice if you know already what systems need events. You also have full control on the order of delivering (which may be relevant at times). It works best if there are a fixed and not too many receivers for an event. Second way also has a bit more flexibility, you could pass other data into the call, or collect returned information, for example. One example is to “give away” a key-press. You try a number of spots that may want a key-press, and the first one that accepts the key ends the sequence (everybody after that never receives the key-press).

I use a state system like above along with a keyboard handler.
This allows me to set the state in the event handler and to make use of it in the loop area where everything is processed. That way regardless what game state I have access to it and don't need to write event code for each state of the game. Of course this could be expanded to have stuff like a string capture so you can use it for also capturing text entry.


class keyboardhandler
{
private:
    bool keystate[256];
    bool clicked[256];
public:
    keyboardhandler(){for(int c=0;c<255;c++){keystate[c]=0;clicked[c]=0;}};
    void setstate(SDL_Scancode key, bool state){keystate[key]=state;clicked[key] = state==false?true:false;}
    bool isPressed(SDL_Scancode key){return keystate[key];}
    bool wasClicked(SDL_Scancode key){return clicked[key];}
    void resetClicked(SDL_Scancode key){clicked[key]=false;}
};

To make use of it:

case SDL_KEYDOWN:
{
      kb_handler.setstate(Event.key.keysym.scancode,SDL_PRESSED);
      break;
}

and

case SDL_KEYUP:
{
      kb_handler.setstate(Event.key.keysym.scancode,SDL_RELEASED);
      break;
}

You can then use isPressed outside the event handler to check the current state of the key.
You can check if it was clicked then reset it. The resetClicked isn't built into the wasClicked to allow checks in multiple areas. That way you can reset it when done with it.

Advertisement