Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » From A4 to A5: questions (console window, key presses,timers/sprite animation)

This thread is locked; no one can reply to it. rss feed Print
From A4 to A5: questions (console window, key presses,timers/sprite animation)
alex Ioan
Member #12,015
June 2010

Ok I managed to install and configure A5 on MSVS 2010...
Using allegro-5.0.3-monolith-mt-debug.dll for debug and allegro-5.0.3-monolith-mt.dll for release.

First question: Are these the good dll's I should be using if I want to distribute my game to other PCs ?

Second question: I see A5 brings a console window with it every time I run the project, in debug and even in release. How can I remove the window in release only ?

Third question:

this is my A4 menu:

while (!key[KEY_ESC])
   {rest(5);
       if (key[KEY_1])
     {//play }
     if (key[KEY_2])
     {//load }

how would this work in A5 ? I read about the events stuff but I can't seem to grasp the concept for single key presses like menu navigation.

Oww and how can I get input from the user? I now use:

#SelectExpand
1string edittext; 2string::iterator iter = edittext.begin(); // string iterator 3int caret = 0; // tracking purposes yarr! 4bool insert = true; 5if (player.getname()=="") 6 {textout_ex( screen, blood, "ENTER YOUR NAME:", 100, 65, white,-1); 7 do {rest(1); while(keypressed()) 8 { int newkey = readkey(); 9 char ASCII = newkey & 0xff; 10 char scancode = newkey >> 8; 11 12 // a character key was pressed; add it to the string 13 if(ASCII >= 32 && ASCII <= 126) 14 { // add the new char, inserting or replacing as need be 15 16 if(insert || iter == edittext.end()) 17 iter = edittext.insert(iter, ASCII); 18 else 19 edittext.replace(caret, 1, 1, ASCII); 20 21 // increment both the caret and the iterator 22 sound.playclick1(); 23 caret++; 24 iter++; 25 26 } 27 // some other, "special" key was pressed; handle it here 28 else 29 switch(scancode) 30 { case KEY_DEL: 31 if(iter != edittext.end()) iter = edittext.erase(iter); 32 break; 33 case KEY_BACKSPACE: 34 if(iter != edittext.begin()) 35 { sound.playclick2(); 36 caret--; 37 iter--; 38 iter = edittext.erase(iter); } 39 break; 40 case KEY_RIGHT: 41 if(iter != edittext.end()) caret++, iter++; 42 break; 43 case KEY_LEFT: 44 if(iter != edittext.begin()) caret--, iter--; 45 break; 46 case KEY_INSERT: 47 if(insert) insert = 0; else insert = 1; 48 break; 49 default: 50 break; } } 51 52 clear(namebuffer); 53 54 textout(namebuffer, blood, edittext.c_str(), 100, 100, white); 55 blit(namebuffer, screen, 0, 0, 50, 90, 820, 240); 56 57 } while(!(key[KEY_ENTER]||key[KEY_ENTER_PAD])); 58 sound.playclick1(); 59 player.nameset(edittext);}

This is to get the player's name and store in in a class... I really don't think it will work in A5...

4'th Question:
This is how my game loop works in A4:

#SelectExpand
1void increment_speed_counter2() 2{speed_counter2++;} 3END_OF_FUNCTION(increment_speed_counter); 4 5LOCK_VARIABLE(speed_counter2); 6LOCK_FUNCTION(increment_speed_counter2); 7install_int_ex(increment_speed_counter2,BPS_TO_TIMER(100)); 8 9while (speed_counter2 > 0) 10{if (key[KEY_UP]||key[KEY_W]) 11 {player.move(8); } //this changes the player's X position via a class 12 13speed_counter2--; //this was the logic loop 14} 15 16if(player.Direction()==8) 17{} //drawing of sprite depending on what frame it is at. 18 19if(bla bla) 20{} //this is also where I do damage handling stuff, sounds etc 21 22if(drawingtoscreen==1) 23{draw all the different stuff on to a buffer then on to the screen.} 24}

so the question is... the same principle applies in A5 ? logic check then drawing stuff?

That would be all , thanks in advance for your help :)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

First off, please use consistent indentation - don't have code on the same line after an opening brace, line up code blocks, and indent every time you enter a new block. It makes it so much more pleasant to read (and help fix your problems).

ALEXAROTH said:

First question: Are these the good dll's I should be using if I want to distribute my game to other PCs ?

If you're linking to the libraries that came with them, then yes those are the dll's you want to distribute with your program.

ALEXAROTH said:

Second question: I see A5 brings a console window with it every time I run the project, in debug and even in release. How can I remove the window in release only ?

There should be a setting in MSVC that allows you to change whether the program is compiled as a console program or a graphical program. Look for subsystem::windowed or something like that in your settings.

ALEXAROTH said:

Third question:

this is my A4 menu:

while (!key[KEY_ESC])
   {rest(5);
       if (key[KEY_1])
     {//play }
     if (key[KEY_2])
     {//load }

how would this work in A5 ? I read about the events stuff but I can't seem to grasp the concept for single key presses like menu navigation.

If you want to know whether a key is up or down, there are two ways to detect this in Allegro 5.
1) Use ALLEGRO_EVENT_KEY_DOWN and ALLEGRO_EVENT_KEY_UP to track when the keys are pressed and released (and therefore, when they are up or down).
2) Use al_get_keyboard_state and al_key_down. The problem with these is that they will never contain the substates of the keys between checks to al_get_keyboard_state. If you use method 1, you will never have this problem.

ALEXAROTH said:

Oww and how can I get input from the user? I now use:
...
This is to get the player's name and store in in a class... I really don't think it will work in A5...

Use al_wait_for_event and check the event type for equivalence to ALLEGRO_EVENT_KEY_CHAR. It will work in A5 just fine...

ALEXAROTH said:

4'th Question:
This is how my game loop works in A4:
...Code...
so the question is... the same principle applies in A5 ? logic check then drawing stuff?

Yes, in A5 you process events until there aren't any, and for each tick of the timer you process your logic and set a redraw flag. Then when you're done with all the events, you check your redraw flag and draw if necessary.

ALEXAROTH said:

That would be all , thanks in advance for your help

You'll probably want to look at several things from the manual :
1) Events
2) Keyboard

You should also take a look at the tutorials for A5 on the wiki, and the Porting guide from A4 to A5 on the wiki.

alex Ioan
Member #12,015
June 2010

Thanks for the response !

I got the release version working without the console !
If other MSVS users: Project Properties->Linker->System->Windows

But I still can't figure out how to do the menu navigation...
I mean I know how to check if a key was pressed and released but I tried thinking about implementing it into making a menu and still can't figure out how to make a simple menu with multiple submenus. Am I broken ? even in A4 I did some stupid loops inside more loops waiting for a keypress... Any concept ideas on how to make such a menu ?

"Use al_wait_for_event and check the event type for equivalence to ALLEGRO_EVENT_KEY_CHAR."
in my example, should I use al_wait_for_event instead of while (keypressed()) ?

and what do to about

int  newkey   = readkey();

?

and

switch(scancode)
 30            {    case KEY_DEL: //....

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

#SelectExpand
1class Menu; 2 3class MenuItem { 4private : 5 int x; 6 int y; 7 int w; 8 int h; 9 string text; 10 Menu* submenu; 11public : 12 MenuItem(int xpos , int ypos , int width , int height , string textstr) : 13 x(xpos), 14 y(ypos), 15 w(width), 16 h(height), 17 text(textstr), 18 submenu(0) 19 {} 20 void SetPosition(int xpos , int ypos , int width , int height) { 21 x = xpos; 22 y = ypos; 23 w = width; 24 h = height; 25 if (submenu) {submenu->SetPosition(x + w , y);} 26 } 27} 28 29class Menu { 30private : 31 int x; 32 int y; 33 int w; 34 int h; 35 vector<MenuItem*> items; 36public : 37 Menu(int xpos , int ypos , int width , int height) : 38 x(xpos), 39 y(ypos), 40 w(width), 41 h(height), 42 items() 43 {} 44 void SetPosition(int xpos , int ypos) { 45 x = xpos; 46 y = ypos; 47 int ix = xpos; 48 int iy = ypos; 49 for (int i = 0 ; i < items.size() ; ++i) { 50 items[i]->SetPosition(ix , iy , w , h); 51 } 52 } 53} 54 55 56 57void MenuItem::SetMenu(Menu* menu) { 58 submenu = menu; 59 if (submenu) {submenu->SetPosition(x + w , y);} 60}

That should give you a basic idea of a setup for a menu. You'll have to implement hit checks and drawing yourself.

ALEXAROTH said:

"Use al_wait_for_event and check the event type for equivalence to ALLEGRO_EVENT_KEY_CHAR."
in my example, should I use al_wait_for_event instead of while (keypressed()) ?

Yes, you can use al_is_event_queue_empty to check if there are any events in the queue. When you get a KEY_CHAR event, send the keycode and the unichar field to your input object to be processed. Check the keycode first to process things like left/right/backspace/delete and if the keycode wasn't used then check the unichar field.

I'm not totally sure how unicode works, but I think you can get away with checking to see if the value is greater than or equal to 32 then I think it will be a printable character. You'll want to take a look at the ALLEGRO_USTR type.

alex Ioan
Member #12,015
June 2010

#SelectExpand
1 2string edittext; 3string::iterator iter = edittext.begin(); 4int caret = 0; 5bool insert = true; 6if (1) 7 {ALLEGRO_EVENT ev; 8 do { al_wait_for_event(event_queue, &ev); 9 if (ev.type == ALLEGRO_EVENT_KEY_CHAR) 10 { 11 int newkey = ev.keyboard.unichar; 12 char ASCII = newkey & 0xff; 13 char scancode = ev.keyboard.keycode; 14 15 // a character key was pressed; add it to the string 16 if(ASCII >= 32 && ASCII <= 126) 17 { // add the new char, inserting or replacing as need be 18 19 if(insert || iter == edittext.end()) 20 iter = edittext.insert(iter, ASCII); 21 else 22 edittext.replace(caret, 1, 1, ASCII); 23 24 // increment both the caret and the iterator 25 26 caret++; 27 iter++; 28 29 } 30 // some other, "special" key was pressed; handle it here 31 else 32 switch(scancode) 33 { case ALLEGRO_KEY_DELETE: 34 if(iter != edittext.end()) iter = edittext.erase(iter); 35 break; 36 case ALLEGRO_KEY_BACKSPACE: 37 if(iter != edittext.begin()) 38 { 39 caret--; 40 iter--; 41 iter = edittext.erase(iter); } 42 break; 43 case ALLEGRO_KEY_RIGHT: 44 if(iter != edittext.end()) caret++, iter++; 45 break; 46 case ALLEGRO_KEY_LEFT: 47 if(iter != edittext.begin()) caret--, iter--; 48 break; 49 case ALLEGRO_KEY_INSERT: 50 if(insert) insert = 0; else insert = 1; 51 break; 52 default: 53 break; } } 54 55 56 57 al_draw_text(font, al_map_rgb(255,255,255), 20,20,ALLEGRO_ALIGN_LEFT,edittext.c_str()); 58 59 al_flip_display(); 60 } while(1);

EDIT: Code above works quite well !

new question:
Error 1 error C2664: 'al_stop_sample' : cannot convert parameter 1 from 'ALLEGRO_SAMPLE *' to 'ALLEGRO_SAMPLE_ID *' c:\users\alexaroth\documents\visual studio 2010\projects\homeless bloodbath a5\homeless bloodbath a5\sound.cpp
why ? :(

AMCerasoli
Member #11,955
May 2010
avatar

You need to send an ALLEGRO_SAMPLE_ID, not just an ALLEGRO_SAMPLE.

When you play a sample using

al_play_sample(ALLEGRO_SAMPLE *spl, float gain, float pan, float speed,
   ALLEGRO_PLAYMODE loop, ALLEGRO_SAMPLE_ID *ret_id)

you need to set an ALLEGRO_SAMPLE_ID.

ALLEGRO_SAMPLE_ID * id;
al_play_sample(spl, 1, 0, 1, 1, id);
al_stop_sample(id);

Matthew Leverton
Supreme Loser
January 1999
avatar

The reason is that you can call al_play_sample() many times on the same sample, so the id distinguishes those.

Technically there's some misnomers with the function names, but I think they are easier to understand misnamed.

alex Ioan
Member #12,015
June 2010

another question: why can't I draw text onto a bitmap anymore ? how could I do that ? :D

and: how can I pass arguments ?
like

al_draw_text( font, l_map_rgb(255,255,255), 210,-1,ALLEGRO_ALIGN_LEFT,"You are now level %d",level); }

and a bonus one: is masked_blit gone ? like, the concept of it

also what does al_clear_to_color clear ? the screen ? how can I make it clear a specified bitmap ? //done

note that I have read the A5 tutorials but they don't provide any info on this

EDIT: got the set target function.. but why complicate things ? anyway

Matthew Leverton
Supreme Loser
January 1999
avatar

See al_draw_textf().

The alpha component with the default blender automatically gives you masked_blits. So all you need to do is load a PNG file and those pixels with alpha=0 will be skipped.

A convenience method is provided al_convert_mask_to_alpha() that converts the old pink style bitmaps to an alpha-ready bitmap.

The al_set_target_bitmap() affects the drawing operations.

alex Ioan
Member #12,015
June 2010

so if I have a bmp with pink background it will automatically see the pink as transparent ?

and how exactly would I use al_convert_mask_to_alpha() ?
does it edit the picture file or the one loaded in the memory ?

and I still don't get key presses

I would have

while (!key[KEY_ESC])
{do stuff}

how is that in A5 again ? don't tell me I have to use events here too :(

Matthew Leverton
Supreme Loser
January 1999
avatar

al_convert_mask_to_alpha(bmp, al_map_rgb(255,0,255));

If bmp was an old A4 magic-pink bitmap, it is now an A5 ready alpha bitmap.

ALEXAROTH said:

how is that in A5 again ? don't tell me I have to use events here too

Read the manual section that talks about al_get_keyboard_state().

alex Ioan
Member #12,015
June 2010

al_get_keyboard_state(&kbdstate); 
if (al_key_down(&kbdstate, ALLEGRO_KEY_ESCAPE))

got it thanks ! :D

Although it feels kinda complicated and seems impossible to implement as I wish without adding another loop around the original loop ...

Matthew Leverton
Supreme Loser
January 1999
avatar

Allegro 5 is not as simple for quick & dirty implementations. But it allows you to do more, so the complications are not for nothing. If you really want an old key style function, just do:

bool is_key_pressed(int key)
{
  ALLEGRO_KEYBOARD_STATE s;
  al_get_keyboard_state(&s);
  return al_key_down(&s, key);
}

while (!is_key_pressed(ALLEGRO_KEY_ESCAPE))
{
}

alex Ioan
Member #12,015
June 2010

Yea hopefully timers will work better in A5... I'll probably have some questions for those too :)

thanks for the help so far !

its past midnight here so might stop coding and start reading more tutorials tomorrow.

PS isn't it
while (!is_key_pressed(ALLEGRO_KEY_ESCAPE))

Matthew Leverton
Supreme Loser
January 1999
avatar

alex Ioan
Member #12,015
June 2010

still can't find a work around for the menu... It's not the escape while in a fight type of menu , but more like a simple out of the game menu.

Let's say I have several options, that can be triggered by key presses like: load, options, play, shop etc.

You press let's say "4" to visit the shop (which is a separate function, with it's own .cpp file), then you have multiple sub-menus like buy/sell/back. buy has some other sub-menus and so on.
What would the basic structure of such a menu be ? It seems simple I know but I couldn't figure out a simple structure without multiple loops inside other loops and function re-calling just go back to a sub-menu ....

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

ALEXAROTH said:

Let's say I have several options, that can be triggered by key presses like: load, options, play, shop etc.

You press let's say "4" to visit the shop (which is a separate function, with it's own .cpp file), then you have multiple sub-menus like buy/sell/back. buy has some other sub-menus and so on.

The first thing I came up with is a switchboard. Use a function pointer to store the current menu that you're in, and do stuff based on the return value of the current menu. For the simplest kind of menus (selecting a state), this will work perfectly. For more complicated menus that change settings interactively it should still work as long as you can change the settings inside the menu function. You can easily separate each menu into it's own file if you like, as long as you include the function's declaration in your main source file.

#SelectExpand
1int readkey(ALLEGRO_EVENT_QUEUE* eq) { 2 while (1) { 3 ALLEGRO_EVENT ev; 4 al_wait_for_event(eq , &ev); 5 if (ev.type == ALLEGRO_EVENT_KEY_CHAR) { 6 return ev.keyboard.keycode; 7 } 8 } 9 return 0; 10} 11 12 13int main_menu() { 14 clear_to_color(screen , makecol(0,0,0)); 15 // draw buttons 16 al_flip_display(); 17 al_flush_event_queue(event_queue); 18 while (1) { 19 int keycode = readkey(event_queue); 20 switch (keycode) { 21 case ALLEGRO_KEY_1 : return 1; 22 case ALLEGRO_KEY_ESCAPE : return 0; 23 } 24 } 25 return -1; 26} 27 28int gfx_menu() { 29 // same as main menu except with different options 30} 31 32/// In main 33 34bool in_menu = false; 35 36typedef int (*MENU_FUNC)(); 37MENU_FUNC current_menu = 0; 38 39/// In logic loop 40 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { 41 in_menu = true; 42 current_menu = main_menu; 43 } 44///... 45 while (in_menu) { 46 int retval = current_menu();// call active menu function 47 if (current_menu == main_menu) {// In main menu 48 switch (return) { 49 case 0 : in_menu = false;break;// user cancelled menu 50 case 1 : current_menu = gfx_menu;break; 51 } 52 } 53 else if (current_menu == gfx_menu) {// In graphics menu 54 switch (return) { 55 case 0 : current_menu = main_menu;break;// user escaped out of gfx menu 56 } 57 } 58 }

Go to: