Monday, July 23, 2012

Lesson 4: Event Driven Programming

Deprecation Notice:

I've been updating the lessons now that SDL2 is officially released, please visit my new site on Github that has updated lessons and improved code.


Now that we've learned how to draw images to the screen it's time to learn how to read user input. Our game won't be very good if there's no way to play it! In this lesson we will cover simple event handling using SDL and begin designing a primitive 'main loop'.

Before we begin it's important to mention that the majority of the code being used for this lesson is the code that we've built up from previous lessons, and as such the repeated code will not be shown as it is assumed you have it already and  are using what you're learning here to add on to the previous lesson's code. If you don't have the code, head back to the earlier lessons, or if you already understand the material grab the code from Lesson 3 off Github and let's get started modifying it.

We'll create the renderer and window the same as before, and our LoadImage and ApplySurface functions remain unchanged. The first change to our program is the loading of a different image, note that you will need to change the filepath to match the location of the image relative to the executable on your system, or the program will fail to run.
We also use the same equation as before for centering our image in the window. For this lesson our image will be:
 


Now before we dive into writing our main loop and event handling code, we'll want to get an understanding of how the SDL event system works.

An event is any interaction with the program done by the user: keypresses, mouse motion, mouse presses, joystick movement, window resizing, minimizing or closing, etc. SDL provides a structure for storing these events called SDL_Event. Let's create one now.
Whenever an event occurs it's added to the queue in chronological order. If we want to read an event from this queue we can pull the oldest event using SDL_PollEvent. This may be a bit confusing, hopefully this handy graphic will help make it a bit clearer.


So in this case the user resized the window, then clicked the mouse, then pushed a key. When we call SDL_PollEvent on this queue it will get the event that happened first, or the oldest event, and put it into our SDL_Event structure so that we can look at the event data in our program.

So if each frame of our game we want to process all events in the queue we'll want to loop through until there's nothing left to read, then continue on and do our other stuff like logic and rendering. This is starting to sound like something we could call our main loop!

In each iteration of the loop we'll want to process our event queue, do some program logic and draw the frame and then do it all over again until the user quits.
Next we'll want to do our event polling. Our goal was to run over all the events in the queue each frame, so let's use another while loop, as PollEvent will return 1, 'true', if there are any pending events, so our loop will run until there are no more events in the queue.
First we get an event from the queue with SDL_PollEvent, which we pass an address too as its signature is SDL_PollEvent(SDL_Event*) and then we do whatever we want to with the input. In this case we're just going to quit the program if the user pushes any key, clicks the mouse or closes the window, so if just about anything happens we set quit to true. Note that clicking the X on the window is read as SDL_QUIT.

SDL's event structure is able to read many different types of events and provides all the valid information tied to each event that may be needed in deciding what to do with the input. For more information on the various event types and the data that comes with them, check out the SDL_Event documentation.

The next step in our loop would be to do various calculations that our program needs to do, such as determining movement, collision outcomes and etc. However since our program is very primitive we don't need to do any logic at the moment, so we'll continue on to rendering.
The code is identical to before, but we must be sure each time to clear the screen before drawing our new scene or we could have images left over from previous frames start showing up.

You'll want to wrap up the program by destroying the texture, renderer and window and quit SDL.

When you run the program you should be able to quit by clicking the X on the window, clicking in the window or pressing a key while the window is selected. You may also notice something a bit interesting when running the program if you check its CPU usage. If you've seen tutorials where the main loop is discussed or have written SDL1.2 code you'd expect that our program for this lesson would max out one of your CPU cores because there's no framerate limiting being done. This is no longer the case with our program as we have created our renderer with the SDL_PRESENTVSYNC flag which tells the renderer to delay and match the framerate of our monitor, letting SDL take care of the framerate limiting for us, and letting us skip writing a line or two of code.

Lesson 4 Extra Challenge!

Try getting the image to move on the screen.
Hint

End of Lesson 4: Event Driven Programming

Thanks for joining me! I'll see you again soon in Lesson 5: Clipping Sprite Sheets

6 comments:

  1. Tiny typo, there's a ";" after:
    bool quit = false

    Great tutorial.

    ReplyDelete
  2. I'd like to say that the image depicting the event handling process says that it's an event STACK, where in reality it's a QUEUE. A small mistake in an otherwise great tutorial. I've never used SDL and am learning it for the first time and this tutorial really helps with that.

    ReplyDelete
  3. Hi!
    Help me! I set this up in CodeBlocks and I can compile and run it, but it does nothing to my input ( no keypress detection and clikcing on the headline's ecit button and no mouse button press)

    ReplyDelete
    Replies
    1. Have you double checked your code against the lesson code on Github? It may also help to look at the updated version of this lesson: http://twinklebear.github.io/sdl2%20tutorials/2013/08/20/lesson-4-handling-events/ .

      If neither of those help it's hard to tell without seeing your code, you could post it somewhere like https://gist.github.com/ and I can take a peek.

      Delete