|
In this post, I want to present remaining important SDL2 functions that were used in Araknoid coding sessions.
First, one more SDL object type.
SDL_Event – a grouping of objects that refer to user input events. Objects of this type are declared by the programmer but are filled with meaningful data by a special function, SDL_PollEvent()
SDL_PollEvent()
SDL_PollEvent(&event)
In SDL, when the user moves a mouse, presses a key on the keyboard etc., an input event of appropriate type is added to the event queue. New events are added to the queue on top of previous ones all the time as long as the user interacts with their input devices.
The function in question, SDL_PollEvent(), accesses the topmost (the most recent) event and removes it from the queue. It takes one parameter of type SDL_Event to which it assigns event data of the event that is currently being accessed. You can then extract event details (such as mouse x- and y-positions, which key on the keyboard was pressed etc.) by accessing member variables of the SDL_Event object. The next time you run the SDL_PollEvent() function, it will access the next event in the queue (which is now on the top as the topmost one has been removed) and remove it. When the entire queue has been emptied or was empty to begin with, SDL_PollEvent() returns 0.
SDL_PollEvent() is not aware of what event it is accessing but since the event itself carries a type (accessible via the data member .type), you can include if-statements to check for the required type and perform actions. That is the basic idea: we use a while-loop to scan the entire event queue removing events from it in the process until it becomes empty. As long as there still are events in the queue, we check the current event’s type and perform required actions accordingly.
Here’s an example how event polling can be used:
SDL_Event event;
while (true)
{
SDL_PollEvent(&event);
if (event.type == SDL_QUIT)
break;
};
We declare an object of type SDL_Event. Then we run a while loop as many times as needed; on each run, we execute SDL_PollEvent() which takes the topmost event off the queue. If that event is of type SDL_QUIT (which occurs whenever the X button in the window has been pressed), break the loop and proceed to whatever code follows.
If you replace the SDL_Delay(3000) line in the previous post with the code chunk presented here, the window will no longer be “frozen”. Since the SDL is no longer paused, you will be abke to move the window. In addition, you will be able to close the window by clicking the X button.
To further exemplify the use of event polling, let’s make the sprite follow cursor position in the window. Here is the modified code:
#include "SDL.h"
int main(int argc, char* argv[])
{
bool quit = false;
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindow("Sprite", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320, 640, SDL_WINDOW_OPENGL);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_WINDOW_OPENGL);
SDL_Surface* image = SDL_LoadBMP("sprites.bmp");//the sprite sheet must be placed in the same folder as project working directory (normally the folder that contains the *.vcxproj file)
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, image);
SDL_Rect clip_orig = { 208, 4, 140, 194 };
SDL_Event event;
SDL_SetRenderDrawColor(renderer,255,255,255,0);
while (!quit)
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEMOTION:
SDL_RenderClear(renderer);
SDL_Rect clip_dest = { event.motion.x, event.motion.y-40, 40, 40 };
SDL_RenderCopy(renderer, texture, &clip_orig, &clip_dest);
SDL_RenderPresent(renderer);
break;
}
};
//deallocate resources
SDL_DestroyTexture(texture);
SDL_FreeSurface(image);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
window = nullptr;
renderer = nullptr;
image = nullptr;
texture = nullptr;
SDL_Quit();
return 0;
}
The biggest change is that we now check for two event types, SDL_QUIT and SDL_MOUSEMOTION. SDL_MOUSEMOTION allows to access current mouse position via two special data members, .motion.x and .motion.y.
Each time we detect mouse motion, we redraw the tiny copy of the sprite (notice how the SDL_RenderCopy() has been moved inside the switch statement under mouse motion case). Each time we define a new SDL_Rect relative to current mouse position and draw the image there. Needless to say, SDL_RenderPresent() is necessary to bring out the backbuffer to the window each time.
Note that another function, SDL_RenderClear() is used each time we redraw the image. This function clears the screen by removing everything that has been drawn, making it blank. If we didn’t do this every time, we would see multiple copies of the sprite drawn on top of each other; comment out line 23 to see the effect.
Function SDL_SetRenderDrawColor() sets the default renderer colour. This is the colour that is applied to the screen when you clear the screen using SDL_RenderClear() and also when drawing basic shapes using functions like SDL_RenderFillRect() etc. In this case, default renderer colour is set to white.
That’s it. Last two posts covered the most important SDL2 functions that are used for drawing sprites on the screen.

About Rokas Paulauskas
2014 Programming
|