Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [ALLEGRO 5] I am having trouble with getting my character to stand still when...

Credits go to Edgar Reynaldo and Thomas Fjellstrom for helping out!
This thread is locked; no one can reply to it. rss feed Print
[ALLEGRO 5] I am having trouble with getting my character to stand still when...
cpp_4_life
Member #12,389
November 2010

Hi, everyone I am having a little trouble with the new Allegro 5. Any way, I am making a game and I have finally got the character to move smoothly. But I want it to stand still when the left key is not pressed, and the right key is not pressed. But it doesn't seem to work, when I let go of both the left or the right it stays at the last position it was running, and it doesn't stand normally. It used to work with Allegro 4, but the API has been revamped so I have to learn it again. Here is the code below:

#SelectExpand
1#include <allegro5\allegro.h> 2#include <allegro5\allegro_image.h> 3bool doexit = false; 4int x = 0; 5int y = 117; 6int xpos = 405; 7const float fps = 20; 8bool redraw = false; 9bool rightpress = false; 10bool leftwaslast = false; 11bool rightwaslast = true; 12int main(void) 13{ 14 ALLEGRO_BITMAP* buffer; 15 ALLEGRO_DISPLAY* screen; 16 ALLEGRO_EVENT_QUEUE* event_queue; 17 ALLEGRO_BITMAP* bck; 18 ALLEGRO_BITMAP* right; 19 ALLEGRO_TIMER* timer; 20 int retval = al_init(); 21 if (!retval) 22 { 23 return 0; 24 } 25 screen = al_create_display(256, 192); 26 if (!screen) 27 { 28 return 0; 29 } 30 if (!al_install_keyboard()) 31 { 32 return 0; 33 } 34 timer = al_create_timer(1.0 / fps); 35 36 bool retval2 = al_init_image_addon(); 37 if (!retval2) 38 return 0; 39 buffer = al_create_bitmap(256, 192); 40 if (!buffer) 41 return 0; 42 bck = al_load_bitmap("background.bmp"); 43 right = al_load_bitmap("right.bmp"); 44 if (!bck || !right) 45 return 0; 46 al_set_app_name("Metriod Game"); 47 al_set_window_title(screen, "Metriod Game"); 48 event_queue = al_create_event_queue(); 49 al_register_event_source(event_queue, al_get_keyboard_event_source()); 50 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 51 al_start_timer(timer); 52 while (1) 53 { 54 al_set_target_bitmap(buffer); 55 al_draw_bitmap(bck, 0, 0, 0); 56 al_set_target_bitmap(buffer); 57 al_convert_mask_to_alpha(right, al_map_rgb(255, 0, 255)); 58 al_draw_bitmap_region(right, xpos, 0, 37, 40, x, y, 0); 59 al_set_target_bitmap(al_get_backbuffer(screen)); 60 al_draw_bitmap(buffer, 0, 0, 0); 61 al_flip_display(); 62 ALLEGRO_EVENT ev; 63 al_wait_for_event(event_queue, &ev); 64 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) 65 { 66 al_destroy_timer(timer); 67 return 0; // End the game! 68 } 69 70 71 if (ev.type == ALLEGRO_EVENT_TIMER) 72 { 73 redraw = true; 74 75 if (rightpress) 76 { 77 x += 4; 78 79 if (xpos == 405) 80 { 81 al_rest(0.001); 82 xpos = 0; 83 84 } 85 else if (xpos == 0) 86 { 87 al_rest(0.001); 88 89 xpos = 37; 90 91 } 92 else if (xpos == 37) 93 { 94 al_rest(0.001); 95 96 xpos = 75; 97 } 98 else if (xpos == 75) 99 { 100 al_rest(0.001); 101 102 xpos = 117; 103 } 104 else if (xpos == 117) 105 { 106 al_rest(0.001); 107 108 xpos = 159; 109 } 110 else if (xpos == 159) 111 { 112 al_rest(0.001); 113 114 xpos = 202; 115 } 116 else if (xpos == 202) 117 { 118 al_rest(0.001); 119 120 xpos = 237; 121 } 122 else if (xpos == 237) 123 { 124 al_rest(0.001); 125 126 xpos = 276; 127 } 128 else if (xpos == 276) 129 { 130 al_rest(0.001); 131 132 xpos = 317; 133 } 134 else if (xpos == 317) 135 { 136 al_rest(0.001); 137 138 xpos = 359; 139 } 140 else if (xpos == 359) 141 { 142 al_rest(0.001); 143 144 xpos = 0; 145 } 146 rightpress = false; 147 } 148 } 149 else 150 { 151 if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT) 152 { 153 rightpress = true; 154 rightwaslast = true; 155 } 156 else 157 { 158 159 if (ev.keyboard.keycode != ALLEGRO_KEY_UP && ev.keyboard.keycode != ALLEGRO_KEY_DOWN) 160 { 161 if (rightwaslast) 162 { 163 164 if (rightwaslast) 165 { 166 xpos = 405; 167 } 168 else if (leftwaslast) 169 { 170 xpos = 468; 171 } 172 173 } 174 } 175 } 176 177 178 } 179 if (redraw && al_is_event_queue_empty(event_queue)) 180 { 181 redraw = false; 182 } 183 184 185 186 } 187 return 0; 188}

Mark Oates
Member #1,146
March 2001
avatar

put your code in <code></code>

cpp_4_life
Member #12,389
November 2010

Sorry about that, some other forums use the [code] syntax. :)

Edgar Reynaldo
Member #8,592
May 2007
avatar

Well, for one thing, you are checking ev.keyboard.keycode when you don't know for sure that the ev.type was ALLEGRO_EVENT_KEY_DOWN or ALLEGRO_EVENT_KEY_UP. At best, you get lucky, and at worst, you access random garbage due to other data being in the union.

Another thing, you only need to call al_convert_mask_to_alpha on your right bitmap once. Don't call it over and over again in your drawing loop.

What is the purpose of all of these blocks?

else if (xpos == blah) {
   al_rest(0.001);
   xpos = blah2;
}

Organize your code into logical sections :

#SelectExpand
1ALLEGRO_EVENT ev; 2al_wait_for_event(event_queue , &ev); 3switch(ev.type) { 4 case ALLEGRO_EVENT_KEY_DOWN : 5 if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT) {rightpress = true;} 6 if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT) {leftpress = true;} 7 break; 8 case ALLEGRO_EVENT_KEY_UP : 9 if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT) {rightpress = false;} 10 if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT) {leftpress = false;} 11 break; 12 case ALLEGRO_EVENT_TIMER : 13 redraw = true; 14 break; 15} 16 17if (rightpress) { 18 x += 4; 19 if (x > blah) {x = blah;} 20} 21if (leftpress) { 22 x -= 4; 23 if (x < blah2) {x = blah2;} 24} 25 26 27if (redraw) { 28 draw_stuff(); 29}

cpp_4_life
Member #12,389
November 2010

Thanks for the post, the purpose of those blocks is to animate the sprite because it moves through each of the different sprites positions in the sprite sheet. By the way the, your pseudo code has helped my code be more organized but it has worsened the situation. It seems that my character now doesn't move smoothly anymore instead it runs in its standing position. I did some debugging and it seems that the rightpress and the leftpress from your pseudo code example keeps being false.
:-/

Thomas Fjellstrom
Member #476
June 2000
avatar

You do not need to use explicit double buffering in Allegro 5, and on some hardware, drawing to ALLEGRO_BITMAPs (that are not a ALLEGRO_DISPLAY backbuffer) is rather slow, so in most cases you do NOT want to double buffer like that.

Especially considering you end up with 2 or more hardware buffers, which is why the al_flip_display call is even needed.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

cpp_4_life
Member #12,389
November 2010

OMG, sorry for posting that your code was faulty, but in fact after doing some indepth scan I by accident had a line of code in the xpos block that kept the rightpress false. So again sorry for wasting your precious time here is the code where I fortuitously found the little mistake that caused a hell of a problem:

#SelectExpand
1if (ev.type == ALLEGRO_EVENT_TIMER) 2 72 { 3 73 redraw = true; 4 74 5 75 if (rightpress) 6 76 { 7 77 x += 4; 8 78 9 79 if (xpos == 405) 10 80 { 11 81 al_rest(0.001); 12 82 xpos = 0; 13 83 14 84 } 15 85 else if (xpos == 0) 16 86 { 17 87 al_rest(0.001); 18 88 19 89 xpos = 37; 20 90 21 91 } 22 92 else if (xpos == 37) 23 93 { 24 94 al_rest(0.001); 25 95 26 96 xpos = 75; 27 97 } 28 98 else if (xpos == 75) 29 99 { 30 100 al_rest(0.001); 31 101 32 102 xpos = 117; 33 103 } 34 104 else if (xpos == 117) 35 105 { 36 106 al_rest(0.001); 37 107 38 108 xpos = 159; 39 109 } 40 110 else if (xpos == 159) 41 111 { 42 112 al_rest(0.001); 43 113 44 114 xpos = 202; 45 115 } 46 116 else if (xpos == 202) 47 117 { 48 118 al_rest(0.001); 49 119 50 120 xpos = 237; 51 121 } 52 122 else if (xpos == 237) 53 123 { 54 124 al_rest(0.001); 55 125 56 126 xpos = 276; 57 127 } 58 128 else if (xpos == 276) 59 129 { 60 130 al_rest(0.001); 61 131 62 132 xpos = 317; 63 133 } 64 134 else if (xpos == 317) 65 135 { 66 136 al_rest(0.001); 67 137 68 138 xpos = 359; 69 139 } 70 140 else if (xpos == 359) 71 141 { 72 142 al_rest(0.001); 73 143 74 144 xpos = 0; 75 145 } 76 146 rightpress = false; // This was causing the problem I don't know how it got there 77 147 } 78 148 }

Edgar Reynaldo
Member #8,592
May 2007
avatar

I didn't realize you were using xpos to set the 'frame' of your sprite.

I would make a separate animation class, give your object a map<state , Animation*> and then set the state when it needs to change :

#SelectExpand
1 2class Animation { 3protected : 4 ALLEGRO_BITMAP** frames; 5 6 double duration; 7 double frames_per_sec; 8 double frametime; 9 int num_frames; 10 int frame_num; 11public : 12 Animation(int nframes , double total_time) : 13 frames(0), 14 duration(total_time), 15 frames_per_sec(0.0), 16 frametime(0.0), 17 num_frames(nframes), 18 frame_num(0) 19 { 20 frames_per_sec = (double)num_frames/duration; 21 frames = new ALLEGRO_BITMAP*[num_frames]; 22 } 23 void SetFrame(int frame_number , ALLEGRO_BITMAP* bmp) { 24 if ((frame_number >= 0) && (frame_number < num_frames)) { 25 frames[frame_number] = bmp; 26 } 27 } 28 void SetFrameTime(double new_time); 29 void AdvanceFrameTime(double delta_time); 30}; 31 32enum ANIM_STATE { 33 STAND_LEFT = 0, 34 STAND_RIGHT = 1, 35 WALK_LEFT = 2, 36 WALK_RIGHT = 3, 37 RUN_LEFT = 4, 38 RUN_RIGHT = 5 39}; 40 41#include <map> 42using std::map; 43 44class Object { 45protected : 46 map<ANIM_STATE , Animation*> anim_state_map; 47 Animation* current_animation; 48pubilc : 49 void AddAnimationState(ANIM_STATE state , Animation* animation) { 50 anim_state_map[state] = animation; 51 } 52 void SetAnimationState(ANIM_STATE state) { 53 current_animation = anim_state_map[state]; 54 current_animation->SetFrameTime(0.0); 55 } 56 void Update(double tsec) { 57 current_animation->AdvanceFrameTime(tsec); 58 } 59}

I did some debugging and it seems that the rightpress and the leftpress from your pseudo code example keeps being false.

Well, I don't see why that would be true. Add in a print statement under the ALLEGRO_KEY_DOWN case and make sure you are getting keypresses in the first place.

There is one thing wrong with what I posted though, it will process if(rightpress) and if(leftpress) once for each event. To prevent that, process the events in a loop and don't break out of the loop until your redraw flag is set.

Thomas Fjellstrom
Member #476
June 2000
avatar

OMG, sorry for posting that your code was faulty, but in fact after doing some indepth scan I by accident had a line of code in the xpos block that kept the rightpress false. So again sorry for wasting your precious time

Don't worry about it. Most of us aren't really all that high and mighty.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Go to: