Make yer own!

Make yer own!

So you've decided you want to write a game…

  • Home

An Allegro Side Note

Posted in Getting Started, Uncategorized by J Artis
Sep 14 2009
TrackBack Address.

Hey all you Allegro guys! You may or may not have a problem in your project where it seems to flicker – this is casue by it attempting to clear and redraw the screen a hojillion times per second. We can solve this using a technique known as double buffering. Remember how we were drawing directly to the magical “screen” bitmap before? We set up another bitmap, the same SIZE as the screen, and draw onto that instead – and then once every frame we copy that bitmap to the screen. That way we don’t redraw the screen more times than necessary. Ready? Let’s begin!

Allegro helpfully has a function that waits until the screen needs to be redrawn. It’s called vsync(), and all it does is wait until it’s safe to redraw the screen. So the steps we’ll need to take to add this in go something like this:

  1. Make a “buffer” bitmap the same size as our game project. (While we’re at it, let’s change our game from 640×480 to 800×600.)
  2. Change our drawing code to draw to the buffer, not the screen
  3. In our main update loop, call vsync() to wait, then draw the buffer to the screen

We’re going to do some reorganization to our code while we’re at it, so we know where things are. First, let’s adress that “how big is our game” part of Step 1: In the init() function, which looks like this…

void init() {
    int depth, res;
    allegro_init();
    depth = desktop_color_depth();
    if (depth == 0) depth = 32;
    set_color_depth(depth);
    res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
    if (res != 0) {
        allegro_message(allegro_error);
        exit(-1);
    }
 
    install_timer();
    install_keyboard();
    install_mouse();
    /* add other initializations here */
}

We’re going to change this line:

res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);

to this:

res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);

Now our game is at the same resolution as our XNA counterpart. The other half of Step 1 was to add a “buffer” bitmap to our program somewhere… how ’bout at the top? Find the function declarations – you know, the section that looks like:

void init();
void deinit();
void DrawSprite(BITMAP* spriteToDraw, int X, int Y);

After that, throw in a blank line, and add this:

// Buffer bitmap for double buffering
BITMAP *buffer;

Now we have a BITMAP object (well, kinda – we have a space cleared out to put one) – we need to set it up at the right size. Back in the init() function, there’s a line that says /* add other initializations here */ – Sounds like a good idea to me. Inside the braces, after that line, add:

    buffer = create_bitmap(800, 600);

Now we have our empty buffer. Let’s change our DrawSprite to point to the buffer and not the screen. In this function:

void DrawSprite(BITMAP* spriteToDraw, int X, int Y)
{
    blit(spriteToDraw, screen, 0, 0, X, Y, spriteToDraw->w, spriteToDraw->h);
}

replace “screen” with “buffer”. That takes care of step two… What’s left? The vsync() call and the drawing of the buffer to the screen. I’ve got a crazy idea… Let’s break out ALL of our drawing into its own function. At the top, with our function declarations, add one more:

void Draw();

And let’s build that function down at the bottom of our program:

void Draw()
{
    clear(buffer);
 
    /* All of our drawing code goes here */
 
    vsync();
    blit(buffer, screen, 0, 0, 0, 0, 800, 600);
}

First it clears the buffer to black, then it… well, it doesn’t do anything yet, but we know where to add all of our sprite drawing and the like. It waits for a screen refresh (that’s the vsync() ) and then it puts the whole buffer right onto the screen.

A thought: We define our title bitmap in the main() function, and due to scope, we can only address it by name in the main() function. We’ll come back to scope later this week, but for now, be aware that we have to move our title bitmap outside of main() – how about up where we have the buffer declared?

// Buffer bitmap for double buffering
BITMAP *buffer;
 
// Title logo
BITMAP *titleBitmap;
 
int main() {

You can get rid of the BITMAP *titleBitmap; line inside the main() function now. Leave the line where we load that image, though – we still need to fill it with the picture we drew.

Now our main game loop should change from this:

    while (!key[KEY_ESC]) 
    {
        clear(screen);
        DrawSprite(titleBitmap, x, y);
    }

to this:

    while (!key[KEY_ESC]) 
    {
        Draw();
    }

And back to our Draw() function, we add the title drawing there.

    /* All of our drawing code goes here */
    DrawSprite(titleBitmap, x, y);

Oh yeah, we use X and Y there – We need to move those outside our main() loop too, or the Draw() function won’t be able to see them.

// Buffer bitmap for double buffering
BITMAP *buffer;
 
// Title logo
BITMAP *titleBitmap;
 
// Title location
int x = 180;
int y = 150;
 
int main() {

Try it – compile it, run it, and see if it does the same thing it did before, and possibly less flickery! You maye want to adjust the X and Y location to re-center the sprite – or not. It is up to you. In any case, we now have a dedicated Draw() function, and we are double-buffering everything. Score one for us!

Share
Tagged as: Allegro
Leave a Comment
Click here to cancel reply.

Recent Posts

  • Number names in Scrabble scoring
  • Analysis of Sinister Sudoku
  • Finding words for HexWords
  • Considering control schemes
  • What is a “Bad-ass” platformer?
Powered by WordPress | “Blend” from Spectacu.la WP Themes Club