Starting with allegro
Alexandre Bencz

I'm starting with game programming, for reasons of a college job, and I'm trying to create a menu for my game, where there is an animation background, but I can not understand how to make animation is playing and make the menu, in fact, I'm not getting to do neither, because I'm losing the idea of the events, and do not know exactly What do do :'(

I would be grateful if someone could explain to me, how can I do this :$

AmnesiA

The easiest way to make an animation display is to create a sprite class which loads all of the individual images used in the animation and then cycles through them each time you receive a timer event. Then just add a Sprite.draw( int x, int y) function that draws the current image to the x and y coordinates supplied.

As for the menu there are several ways to do it, the most noob-friendly would be to draw primitives to make up the look you want for the menu, or, just as easily, draw a menu you like and then draw that image to the screen.

main.cpp

bool redraw = true;
while(!done){ //Game loop
    ALLEGRO_EVENT event;
    al_wait_for_event( event_queue, &event);
    if( event.type == ALLEGRO_EVENT_TIMER){
        redraw = true;
    }

    if( redraw && al_is_event_queue_empty( event_queue)){
        redraw = false;
        mySprite.draw( 10, 10);
        al_flip_display();
    }
}

Sprite.cpp

//frame would be an int to keep track of which frame in the animation you are on.
//image_index would be a vector<ALLEGRO_BITMAP*> to keep track of all of the images
//    in the animation
//image_count would be an int that knows how many frames are in the animation
//All of this would be set up either when the sprite is created or when an
//    init() function was called.
void Sprite::draw( int x, int y){
    al_draw_bitmap( image_index[frame], x, y, 0); //Draw the current image
    if( ++frame >= image_count)                  //Animate the sprite
        frame = 0;
}

Alexandre Bencz

So, I tried to make here, but, not work....
and, I don't know why ??? :(

look my code: https://gist.github.com/senacbcc/6fd79457c36020fd2503

>************************************<
// EDIT
>************************************<

I found the error, but, when I press the D key, the image not desappers, and, just continue the image, how I can make to look like the character is actually walking... and move the image on screen ???

look my code: https://gist.github.com/senacbcc/6fd79457c36020fd2503 ( new version... )

AmnesiA

Your drawing and moving should be in two different sections of code. I'm assuming D is your move right key, so in that case you want to do something like:

if(evento.type == ALLEGRO_EVENT_KEY_DOWN)
{
    switch(evento.keyboard.keycode)
    {
  case ALLEGRO_KEY_D:
            character_x += 4;
            chengeSprite( character_x, character_y);
      break;
    }
}
al_flip_display();

Where character_x and character_y are variables that store your character's location on the screen.

It's really helpful to try to split your code up into logical sections. For example, my main() function in the game I just finished looks like this:

#SelectExpand
239int main( int argc, char** argv){ 240 init(); 241 game_loop(); 242 shutdown(); 243 244 return 0; 245}

And then break up your game loop into similar sections. There is your "step" event which is where you put code that should be executed each frame. For example,

#SelectExpand
111if(event.type == ALLEGRO_EVENT_TIMER){ 112 redraw = true; 113 if( !paused) roomLib.step(); 114}

Next you'll handle your input events, which usually is simply something like

if( event.type == ALLEGRO_EVENT_KEY_DOWN){
    switch( event.keyboard.keycode){
        case ALLEGRO_KEY_UP:
            key[UP] = true;
            break;
        //ETC.
    }
}else if( event.type == ALLEGRO_EVENT_KEY_UP){
    switch( event.keyboard.keycode){
        case ALLEGRO_KEY_UP:
            key[UP] = false;
            break;
        //ETC.
    }
}

After that you'll obviously put any other events you'd like to handle such as character input or window events. Finally, after your game has done all of the "work" it needs to do for that step, it will draw the result so everything's draw function will be neatly together in a section like this:

if( redraw && al_is_event_queue_empty( event_queue)){
    redraw = false;
    roomLib.draw();
    myHud.draw();
    al_flip_display();
}

Obviously you'd have to tweak it to match your code, but you get the idea of grouping, I hope :)

EDIT: In your code you also don't have to have the line if (!al_is_event_queue_empty(fila_eventos)) because next you're already telling the program to wait for an event with al_wait_for_event(fila_eventos, &evento);

Alexandre Bencz

Oook, I got the ideia

https://gist.github.com/senacbcc/6fd79457c36020fd2503

But, when I press the "D" key, the "system" not work.... o.O
haha :'(

Trent Gamblin

You could have a "draw" function that looks something like this (very oversimplified because I can't remember all of your code):

void draw()
{
   al_draw_bitmap(/* draw player here */);
   /* draw other stuff later */
}

Then where you have:

if (redraw) {
   redraw = false;
   al_flip_display();
}

Call the draw() function before al_flip_display(). Then change your "chengeSprite" function so that it doesn't draw anything (draw in the draw() function instead) and finally remove the first call to al_flip_display, the one right after you handle the key events.

AmnesiA

I'm not sure what you mean by that but one issue you should be having is that al_create_sub_bitmap shares drawing memory so when sptTest goes out of scope all of its sub bitmaps are pointing to unallocated space. Instead try using

#SelectExpand
1ALLEGRO_BITMAP* targetBitmap = al_get_target_bitmap(); 2ALLEGRO_BITMAP* tempBitmap = al_load_bitmap( "./data/gb_walk.png"); 3if(!tempBitmap){ //if it didn't load 4 return -1; 5} 6 7//Load series of images into imageIndex 8for( int i = 0; i < imageCount; ++i){ 9 imageIndex.push_back( al_create_bitmap( IMAGE_WIDTH, IMAGE_HEIGHT)); 10 if(!imageIndex[i]){ //if the bitmap couldn't be created 11 return -1; 12 al_set_target_bitmap(imageIndex[i]); 13 al_draw_bitmap_region 14 ( 15 tempBitmap, sx + (IMAGE_WIDTH + offset) * i, sy, 16 IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0, 0 17 ); 18} 19al_set_target_bitmap(targetBitmap);

sx = the x position that the image you want is located on the main bitmap
sy = the y position that the image you want is located on the main bitmap
IMAGE_WIDTH = the width of the sprite
IMAGE_HEIGHT = the height of the sprite
offset = the amount of space between each image on your main bitmap

I noticed you're only increasing the width on your bitmap so each consecutive bitmap you're adding to walk[] will still contain the bitmap that was created before it:
0,0[---]aux
0,0[------]aux
0,0[---------]aux
so you need to do it like i have in my code above.

If this doesn't solve your problem let me know but please use specific errors if you can

Trent Gamblin
AmnesiA said:

I'm not sure what you mean by that but one issue you should be having is that al_create_sub_bitmap shares drawing memory so when sptTest goes out of scope all of its sub bitmaps are pointing to unallocated space.

That's not true. Allocated pointers don't go out of scope. It's a memory leak but it will "work" besides that. As far as I'm concerned his issues are exactly what I said.

EDIT: I should say allocated memory doesn't go out of scope. The "sptTest" variable is lost but its contents are still in memory and so the sub-bitmaps are still valid. It is a good point though that you brought up. The OP will need to destroy that bitmap later to avoid a memory leak. The simplest way is to make it global like the sub-bitmaps.

beoran

To explain this form a more broad perspective: with Allegro5 you will program by reacting to events by changing the state data of your program. It's normally easiest to model the state by having game objects that can be drawn at certain locations and that keep track of which frame of animation they are displaying.

Now, whether or not there there are input events, the program will always simply loop, update the location of the game objects based on their speed and then redraw the screen as is needed.

I hope this explanation is somewhat helpful.

Alexandre Bencz

I understand, and I managed to solve :)
Now is working properly :) *------*

Thanks for the help of all guys ;)

AmnesiA

The "sptTest" variable is lost but its contents are still in memory and so the sub-bitmaps are still valid

So that main sprite is still in allocated memory even after the pointer for it goes out of scope? I did the sub bitmap thing when I started but I was getting errors with it and I assumed it's because it was a sub bitmap trying to get information from a parent bitmap that didn't exist anymore - but you're telling me this is not the case, correct?

Does that mean that it's actually better to use sub-bitmaps for sprites instead of doing it the way I was (using al_draw_bitmap_region)? It seems like it would be since they'd be sharing memory instead of creating their own each time.

Trent Gamblin
AmnesiA said:

So that main sprite is still in allocated memory even after the pointer for it goes out of scope? I did the sub bitmap thing when I started but I was getting errors with it and I assumed it's because it was a sub bitmap trying to get information from a parent bitmap that didn't exist anymore - but you're telling me this is not the case, correct?

Does that mean that it's actually better to use sub-bitmaps for sprites instead of doing it the way I was (using al_draw_bitmap_region)? It seems like it would be since they'd be sharing memory instead of creating their own each time.

If you have something like:

my_bmp = al_load_bitmap();

Or anything that allocates memory and returns a pointer, that memory never "goes out of scope" unless you specifically delete it, in this case with al_destroy_bitmap. The only thing that can go out of scope is the variable, "my_bmp". The memory itself stays there until you free it or exit the program.

For your second question, either method is fine, it depends on how you want to do it. But yes, sub-bitmaps do share memory with the parent so they use very little memory of their own. They still have to be destroyed with al_destroy_bitmap though, because they do use a tiny bit of memory.

beoran

One of the particular points about programming in C and C++, which is different from many other languages, is that you have to manage the memory and other resources allocated by your program yourself. C++ has a few features that help with that, but Allegro is a pure C library, which means you'll have to do memory and resource handling yourself. (Unless you write some C++ around Allegro to help you do it).

The rule to remember is "Open the door, use it and then close it behind you." or "Allocate it, then use it, then free it". Any function that allocates memory should be balanced somewhere in your program by another function that deallocates/frees that memory. Every al_load_bitmap() should be balanced by an al_destroy_bitmap(). Same, every al_create_bitmap() also by an al_destroy_bitmap(), al_load_sample() by al_destroy_sample(), malloc() or calloc() by free(), new by delete, new[] by delete[], fopen by fclose, etc, etc...

I did notice that your game, while it works fine, does leak memory in several places. I blame C++ for clouding your view. Some things in C++, like std::string or std::vector get the memory they allocate deallocated "automatically" in their destructors when they go out of scope. However, this is not true in the general case! C++ is based on C, and that is why, like in C, you will sometimes have to manually deallocate the resources you allocated. C is a language for responsible people who always clean up after themselves. :)

AmnesiA

I thought one of the reasons that people who prefer C are snobby to people who write C++ is that C++ deallocates memory automatically when the variables go out of scope. I just reread that chapter and realize now though that if I dynamically allocate memory I have to delete it. The only time in my game I dynamically allocated memory though I did delete it when the object died so I don't understand where the memory leaks would happen.

So since al_load_bitmap loads a file into an ALLEGRO_BITMAP that means that I have to explicitly delete it before the pointer to it goes out of scope because then I'll lose access to it, right?

Trent Gamblin

Yeah but my terminology was confusing. You don't literally call "delete" on it, you call al_destroy_bitmap. Your reasoning is correct.

AmnesiA

Ahhh, cool. Thank you so much! That's why I love these forums! :)

beoran

Amnesia yes that's the right idea.

One of the many reasons I'm not too excited about C++ is that it doesn't ALWAYS "deallocate memory automatically when the variables go out of scope". It only does that for objects which have been set up specifically to do so using a correct destructor, or if you use objects that have been specifically set up to do so from the C++ library. And even then you have to be careful to set up the destructor correctly and use it in a RAII fashion, what with virtual destructors, and pointers contained in arrays, etc. :/

In C it's simple: you have to clean up every resource you use yourself at the right time. It's consistent too. :)

As for snobs, I'd rather say that some people who people who use C++ are the snobs, with their "C++ is newer and better than C" attitude. C++ can be fine in some cases, but it has tons of complexities and irregularities. C gives you simplicity and consistency at the cost of having to do more work yourself.

And that's why I prefer plain C. For me, the simplicity and consistency of C is just what I like, combined with a good scripting language like mruby or lua to implement the higher level parts of the game.

If you prefer C++, then that is fine, though. However, seeing your previous misunderstandings, I'm getting more and more convinced that it is necessary to become a good C programmer first before you can be a good C++ programmer. The building of the extensions of C++ are built on the foundations of C. So I think it's essential to learn first how to work with the basic foundations of C before going on with the complexities of C++.

Trent Gamblin
beoran said:

One of the many reasons I'm not too excited about C++ is that it doesn't ALWAYS "deallocate memory automatically when the variables go out of scope". It only does that for objects which have been set up specifically to do so using a correct destructor, or if you use objects that have been specifically set up to do so from the C++ library. And even then you have to be careful to set up the destructor correctly and use it in a RAII fashion, what with virtual destructors, and pointers contained in arrays, etc. :/

Objects allocated on the heap always have to be deleted. Always. The only time an object is automatically destructed is if it's on the stack:

if (something) {
   MyObject o;
   o.doStuff();
   // destructor called here
}

So it's not like there are a lot of rules... 1 rule. And that rule is basically the same as C: you don't free stuff allocated on the stack.

beoran

Yes, Trent, that's actually what I was getting at. I'm sometimes not good at communicating. :p

Anyway, I mean that I think that RAII isn't all that useful in the general case of long living resources. They only help you clean up short-lived (funcion or block scoped) resources.

"So it's not like there are a lot of rules" For this one, maybe not. But for C++ as a whole... the C++ standard is about 3x thicker than the C one. That can only be because C++ has about 3x more rules than C has.

Thread #613102. Printed from Allegro.cc