3

I am currently learning SDL and I am trying to create a Pacman game. I'm trying to take it in steps so as not to get bogged down with massive amounts of code.

So far I have created a blank window and rendered a Pacman image onto it. I am able to press the arrow keys and move the Pacman around the window. I have it set up so the Pacman image is stored as an SDL_Texture, which I blit to the window using RenderCopy. Each time the user presses an arrow, I move the coordinates of the image and re render the whole image. This works just fine. Now, however, I want to put some dots on the screen for the Pacman to eat. If I load a dot image and store it as a new texture to blit to the screen along with the Pacman, however, each time I move the Pacman the dot flashes in and out because it is being erased and re rendered along with the Pacman.

My question is, how do I avoid this "flashing"? Can I somehow re render only the Pacman without re rendering the rest of the screen? Or is there another way to do this? I figure I'm also going to have the same problem when I try to create the maze later in the background. How do I make a static background that doesn't flash in and out each time I re render?

Below is my code so far. Forgive me if there is any code of bad form in there. As I said, I am just starting to learn SDL (pretty new to C++ as well), so if there is any glaring "You should never do that!" kind of things in there, I would appreciate anyone pointing it out :)

#include <iostream>
#include <SDL2/SDL.h>
using namespace std;

const int WINDOW_HEIGHT = 480;
const int WINDOW_WIDTH = 640;
const int MOVE_WIDTH = 10;

int main(int argc, const char * argv[])
{
    SDL_Window* mainWindow = NULL; //To hold the main window
    SDL_Renderer* renderer = NULL; //To hold the renderer
    SDL_Rect targetRect; //Rectangle to which pacman image will be drawn
    SDL_Surface* bmpSurface = NULL; //To hold bmp image
    SDL_Texture* bmpTexture = NULL; //To hold bmp image

    //Initialize SDL and check for errors
    if ( SDL_Init(SDL_INIT_EVERYTHING) != 0 )
    {
        cout << "ERROR: could not initialize SDL." << endl;
    }

    //Create a window
    mainWindow = SDL_CreateWindow("BAM", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, 0);

    if (mainWindow == NULL)
    {
        cout << "ERROR: could not initialize mainWindow." << endl;
    }

    //Initialize renderer
    renderer = SDL_CreateRenderer(mainWindow, -1, SDL_RENDERER_ACCELERATED);

    //Load image and store in an SDL_Surface
    bmpSurface = SDL_LoadBMP("/Users/billgrenard/Desktop/Programs/SDL/SDL_KeyPresses/SDL_KeyPresses/pacman_closed.bmp");
    if ( bmpSurface == NULL )
    {
        cout << "ERROR: could not load bmp file." << endl;
    }

    //Convert surface to texture for rendering
    bmpTexture = SDL_CreateTextureFromSurface(renderer, bmpSurface);
    if ( bmpTexture == NULL )
    {
        cout << "ERROR: could not convert bmp surface." << endl;
    }

    SDL_FreeSurface(bmpSurface);

    //Define rectangle where pacman image is to be blitted
    targetRect.w = 30;
    targetRect.h = 30;
    targetRect.x = (WINDOW_WIDTH/2) - (targetRect.w/2);
    targetRect.y = (WINDOW_HEIGHT/2) - (targetRect.h/2);


    //Main game loop
    while (1)
    {
        SDL_Event e;
        if (SDL_PollEvent(&e))
        {
            //Quit when user x's out the window
            if (e.type == SDL_QUIT)
            {
                break;
            }

            //If user presses a key enter switch statement
            else if( e.type == SDL_KEYDOWN )
            {
                switch ( e.key.keysym.sym ) {
                    //If user presses up arrow and the resulting move is inside the window, then move the Pacman's position
                    case SDLK_UP:
                        if ( targetRect.y - MOVE_WIDTH > 0 )
                        {
                            targetRect.y -= MOVE_WIDTH;
                        }

                        break;

                    //If user presses down arrow and the resulting move is inside the window, then move the Pacman's position
                    case SDLK_DOWN:
                        if ( targetRect.y + MOVE_WIDTH < (WINDOW_HEIGHT - targetRect.w) )
                        {
                            targetRect.y += MOVE_WIDTH;
                        }

                        break;

                    //If user presses right arrow and the resulting move is inside the window, then move the Pacman's position
                    case SDLK_RIGHT:
                        if ( targetRect.x + MOVE_WIDTH < (WINDOW_WIDTH - targetRect.w) )
                        {
                            targetRect.x += MOVE_WIDTH;
                        }

                        break;

                    //If user presses left arrow and the resulting move is inside the window, then move the Pacman's position
                    case SDLK_LEFT:
                        if ( targetRect.x - MOVE_WIDTH > 0 )
                        {
                            targetRect.x -= MOVE_WIDTH;
                        }

                        break;

                    default:
                        break;
                }
            }
        }

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, bmpTexture, NULL, &targetRect);
        SDL_RenderPresent(renderer);       
    }

    SDL_DestroyWindow(mainWindow);
    SDL_DestroyTexture(bmpTexture);
    SDL_DestroyRenderer(renderer);
    SDL_Quit();

    return 0;
}

EDIT: In answer to raser's comment, here is the link where I found the PollEvent example: http://wiki.libsdl.org/SDL_CreateRenderer?highlight=%28%5CbCategoryAPI%5Cb%29%7C%28SDLFunctionTemplate%29

wgrenard
  • 187
  • 12
  • How are you rendering the dots? – Nick Beeuwsaert Jan 11 '14 at 06:02
  • I loaded the dot image and stored it in a new texture. Then I called a second RenderCopy (right after the RenderCopy I used for the Pacman image) using the same renderer, but rendering the dot texture and using a different targetRect.Then I just kept the same RenderPresent function which I already have in the code to render both the dot and the Pacman. – wgrenard Jan 11 '14 at 06:11
  • Huh I wrote a test just now to see if it would do that and it doesn't. Is the pacman flickering along with the dots or just the dots? – Nick Beeuwsaert Jan 11 '14 at 06:15
  • I think the problem might be in the way you are processing events. Usually SDL_PollEvent is called until it returns 0, so you don't get a buildup of events. – Nick Beeuwsaert Jan 11 '14 at 06:23
  • Well, the pacman is moving so the flicker isn't a problem. When I re render the Pacman disappears from its old position and appears in the new position, which is what I want. But the dot also disappears and reappears as I re render as well. But since the dot isn't being moved it just looks like it disappears and comes back. – wgrenard Jan 11 '14 at 06:32
  • And I copied the poll event loop directly from SDL's documentation examples. I suppose I could have messed something up in the process of transitioning though. – wgrenard Jan 11 '14 at 06:33
  • Which examples? I don't think I've ever seen `if(SDL_PollEvent(&evt))` in the SDL documentation. And can you provide the code snippet that is causing the problem, with the dot drawing code in it? – Nick Beeuwsaert Jan 11 '14 at 06:41
  • 1
    The PollEvent example I found under the documentation for the SDL_CreateRenderer function. I just checked it again and it looks like my code. Anyway, I just put some code together to post for you and the dot is no longer flickering. I think I found my problem. Somewhere in the middle there I was trying to add some animation (an opening and closing mouth on the Pacman) so I rendered two different Pacman images with SDL_Delay(90) in between them. That delay between renderings must have been what was going on. So stupidly obvious in hindsight. – wgrenard Jan 11 '14 at 07:01
  • That example is used to demonstrate `SDL_CreateRenderer` and only checks for a `SDL_QUIT` event. I don't think you should take the example too seriously. At not least regarding `SDL_PollEvent` Take a look here : http://wiki.libsdl.org/SDL_PollEvent?highlight=%28%5CbCategoryAPI%5Cb%29%7C%28SDLFunctionTemplate%29 – olevegard Jan 11 '14 at 20:21
  • Okay, I do remember seeing that example now, and when I first saw it I wondered what the difference was between the two. To me it seems like whether you use while(SDL_PollEvent(&event)) or use if(SDL_PollEvent(&event)) inside a loop, you get the same result. Though the example in your link certainly seems more succinct than mine. Is this why it is preferred? – wgrenard Jan 11 '14 at 20:30

1 Answers1

0

The above method used to render the Pacman will actually work just fine for rendering the dots to the screen. Simply store an image for the dot in a new texture, create an SDL_Rect to hold this texture, and then use SDL_CreateRenderer to render the dot image to the screen along with the Pacman. You should notice no flashing of the dot between renderings as long as you have not used something like SDL_Delay to slow the framerate.

wgrenard
  • 187
  • 12