Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [A5] Allegro Key Repeating

This thread is locked; no one can reply to it. rss feed Print
[A5] Allegro Key Repeating
Neil Roy
Member #2,229
April 2002
avatar

I'm reprogramming some A4 code and after entering in keyboard code, successfully compiling it, it only detects when I press an arrow key once, but doesn't do anything if I hold it down.

Here's a code snippit:

      al_wait_for_event(queue, &event);

      if(event.type == ALLEGRO_EVENT_KEY_DOWN) {
         al_get_keyboard_state(&keys);
         if(event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
            done = TRUE;
         else if(event.keyboard.keycode == ALLEGRO_KEY_UP && pacman.y > 0) pacman.y--;
         else if(event.keyboard.keycode == ALLEGRO_KEY_DOWN && pacman.y < (h-al_get_bitmap_height(pacman.img))) pacman.y++;
         else if(event.keyboard.keycode == ALLEGRO_KEY_LEFT && pacman.x > 0) pacman.x--;
         else if(event.keyboard.keycode == ALLEGRO_KEY_RIGHT && pacman.x < (w-al_get_bitmap_width(pacman.img))) pacman.x++;
         else if(event.keyboard.keycode == ALLEGRO_KEY_PRINTSCREEN) saveScreenshot();
      }

(using a pacman character in this example, not reprogramming my game though ;))

Anyhow, I need to tap any arrow keys like mad to get it to move at all. I seen some code that had:

if(event.type == ALLEGRO_EVENT_KEY_DOWN || event.type = ALLEGRO_EVENT_KEY_REPEAT)

but when I tried it I got an error about ALLEGRO_EVENT_KEY_REPEAT being undefined. Was this dropped from Allegro 5, or is there something I am missing? Not 100% certain on how to approach this.

Edgar Reynaldo
Member #8,592
May 2007
avatar

I think you should use ALLEGRO_EVENT_KEY_CHAR and then check event.keyboard.keycode.
The ALLEGRO_EVENT_KEY_CHAR has a keyboard.repeat field, where the ALLEGRO_EVENT_KEY_DOWN field does not and I don't believe you'll get ALLEGRO_EVENT_KEY_DOWN for repeated keys.

Edit -

Neil Roy said:

Anyhow, I need to tap any arrow keys like mad to get it to move at all.

Well, you're only moving it one pixel at a time for each key press, what did you expect? Don't you want to just set the direction it is moving for each key press?

torhu
Member #2,727
September 2002
avatar

You have to use ALLEGRO_EVENT_KEY_CHAR if you want to get repeats.

Matthew Leverton
Supreme Loser
January 1999
avatar

KEY_DOWN and KEY_UP represent a physical key being pressed or released. KEY_CHAR indicates some character has been pressed or repeated.

Note that there is not a 1:1 map between KEY_DOWN and KEY_CHAR. Some characters may take multiple KEY_DOWN events to get triggered. Or one KEY_DOWN could trigger multiple KEY_CHARs (repeats, macros, etc...).

Solution #1: use KEY_CHAR

Solution #2: set a flag when receiving KEY_DOWN and clear it when receiving KEY_UP

Relying on repeating keys isn't generally good practice though. So I'd use #2 if you use events.

Solution #3: use the keyboard state functions instead of keyboard events. This is how Allegro 4 worked.

Billybob
Member #3,136
January 2003
avatar

Assuming you have a timer installed:

#SelectExpand
1// Main game loop 2do 3{ 4 ALLEGRO_EVENT ev; 5 6 al_wait_for_event(event_queue, &ev); 7 al_get_keyboard_state(&keys); 8 9 if(ev.type == ALLEGRO_EVENT_TIMER) 10 { 11 if(al_key_down(keys, ALLEGRO_KEY_UP) && pacman.y > 0) pacman.y--; 12 ... 13 } 14 15 ... 16}

There's a tutorial on the wiki (Here) that shows how to install a timer and handle game-logic + drawing.

EDIT: Fixed code.

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

Edgar Reynaldo
Member #8,592
May 2007
avatar

Neil Roy
Member #2,229
April 2002
avatar

Actually I wrote this quickly for a test program I have (pixel perfect collision) and I just needed to move the character (pacman in this test) around until it collides in various ways to see if the codes works.

I just tried setting a flag, and it works, but it seems awful slow at times (I sped up the movement by +2 instead). Especially when drawing rectangles. I draw a rectangle around three bitmaps I am drawing to show the bounding box for collisions and when there is a collision I change the colour of the bounding box from green to red, that really seems to cause a bit of a spike in lag for a moment.

I'm thinking that I may have to ditch the idea of using events altogether or do something differently. This is a pretty simple program.

Billybob
Member #3,136
January 2003
avatar

Small correction to BillyBob's

Thank you, I don't know what I was thinking :P Code corrected.

Neil Roy said:

but it seems awful slow at times

Is your code timed, like my example?

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

Edgar Reynaldo
Member #8,592
May 2007
avatar

Neil Roy said:

I just tried setting a flag, and it works, but it seems awful slow at times (I sped up the movement by +2 instead). Especially when drawing rectangles. I draw a rectangle around three bitmaps I am drawing to show the bounding box for collisions and when there is a collision I change the colour of the bounding box from green to red, that really seems to cause a bit of a spike in lag for a moment.

How often do you draw, and what rate is your timer set at? A simple program like that should be ridiculously fast. Show more code.

Neil Roy
Member #2,229
April 2002
avatar

I haven't tried your new code yet. This works, but lags when you collide a little. Probably my collision code is a little slow, but I couldn't imagine it being THIS slow, it was faster before. I am reading and comparing pixels from the colliding bitmaps, so I am wondering if there is something extra I need to do before reading pixels etc...

main.c
~~~~~~

#SelectExpand
1#define WIDTH 800 2#define HEIGHT 600 3 4#include <stdio.h> 5#include <allegro5/allegro.h> 6#include <allegro5/allegro_image.h> 7#include <allegro5/allegro_primitives.h> 8 9#include "sprite.h" 10#include "sprite_collide.h" 11#include "al_error.h" 12 13 14int main(int argc, char *argv[]) 15{ 16 ALLEGRO_DISPLAY *display = NULL; 17 ALLEGRO_TIMER *timer; 18 ALLEGRO_EVENT_QUEUE *queue; 19 bool redraw = false; 20 bool pressed_key[ALLEGRO_KEY_MAX]; 21 sprite pacman, dot[2]; 22 bool done = false; 23 24 al_init(); 25 al_init_image_addon(); 26 al_init_primitives_addon(); 27 al_install_keyboard(); 28 29 memset(pressed_key, false, sizeof(pressed_key)); 30 31 display = al_create_display(WIDTH, HEIGHT); 32 if(!display) { 33 al_error(AT, display, "al_create_display() failed!"); 34 exit(1); 35 } 36 37 pacman.img = al_load_bitmap("pacman.png"); 38 if(!pacman.img) { 39 al_error(AT, display, "load pacman.png failed!"); 40 done = TRUE; 41 } 42 else { 43 pacman.x = 100; // this should be always be set according to a map 44 pacman.y = 100; // this should be always be set according to a map 45 pacman.collision = FALSE; 46 } 47 48 for(int i=0; i<=1; i++) { 49 dot[i].img = al_load_bitmap("dot.png"); 50 if(!dot[i].img) { 51 al_error(AT, display, "load dot.png failed!"); 52 done = TRUE; 53 } 54 else { 55 dot[i].x = ((al_get_display_width(display) - al_get_bitmap_width(dot[i].img)) / 2) + 50*i; 56 dot[i].y = ((al_get_display_height(display) - al_get_bitmap_height(dot[i].img)) / 2); 57 dot[i].collision = FALSE; 58 } 59 } 60 61 timer = al_create_timer(1.0 / 60); 62 queue = al_create_event_queue(); 63 al_register_event_source(queue, al_get_keyboard_event_source()); 64 al_register_event_source(queue, al_get_display_event_source(display)); 65 al_register_event_source(queue, al_get_timer_event_source(timer)); 66 al_start_timer(timer); 67 68 float h = al_get_display_height(display); 69 float w = al_get_display_width(display); 70 71 ALLEGRO_KEYBOARD_STATE keys; 72 while(!done) { 73 ALLEGRO_EVENT event; 74 al_wait_for_event(queue, &event); 75 76 if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 77 done = TRUE; 78 79 // check for key input and process it 80 if(event.type == ALLEGRO_EVENT_KEY_DOWN) { 81 al_get_keyboard_state(&keys); 82 if(event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) 83 done = TRUE; 84 else if(event.keyboard.keycode == ALLEGRO_KEY_UP) pressed_key[ALLEGRO_KEY_UP] = true; 85 else if(event.keyboard.keycode == ALLEGRO_KEY_DOWN) pressed_key[ALLEGRO_KEY_DOWN] = true; 86 if(event.keyboard.keycode == ALLEGRO_KEY_LEFT) pressed_key[ALLEGRO_KEY_LEFT] = true; 87 else if(event.keyboard.keycode == ALLEGRO_KEY_RIGHT) pressed_key[ALLEGRO_KEY_RIGHT] = true; 88 } 89 if(event.type == ALLEGRO_EVENT_KEY_UP) { 90 al_get_keyboard_state(&keys); 91 if(event.keyboard.keycode == ALLEGRO_KEY_UP) pressed_key[ALLEGRO_KEY_UP] = false; 92 else if(event.keyboard.keycode == ALLEGRO_KEY_DOWN) pressed_key[ALLEGRO_KEY_DOWN] = false; 93 if(event.keyboard.keycode == ALLEGRO_KEY_LEFT) pressed_key[ALLEGRO_KEY_LEFT] = false; 94 else if(event.keyboard.keycode == ALLEGRO_KEY_RIGHT) pressed_key[ALLEGRO_KEY_RIGHT] = false; 95 } 96 97 if(event.type == ALLEGRO_EVENT_TIMER) { 98 if(pressed_key[ALLEGRO_KEY_UP] && pacman.y > 0) pacman.y-=2; 99 else if(pressed_key[ALLEGRO_KEY_DOWN] && pacman.y < (h-al_get_bitmap_height(pacman.img))) pacman.y+=2; 100 if(pressed_key[ALLEGRO_KEY_LEFT] && pacman.x > 0) pacman.x-=2; 101 else if(pressed_key[ALLEGRO_KEY_RIGHT] && pacman.x < (w-al_get_bitmap_width(pacman.img))) pacman.x+=2; 102 103 pacman.collision = FALSE; 104 dot[0].collision = FALSE; 105 dot[1].collision = FALSE; 106 107 // set collision flag on objects that were involved in a collision 108 if(sprite_collide(&dot[0], &pacman)) { 109 dot[0].collision = TRUE; 110 pacman.collision = TRUE; 111 } 112 if(sprite_collide(&dot[1], &pacman)) { 113 dot[1].collision = TRUE; 114 pacman.collision = TRUE; 115 } 116 redraw = TRUE; 117 } 118 119 if(redraw && al_is_event_queue_empty(queue)) { 120 redraw = FALSE; 121 122 al_clear_to_color(al_map_rgb(0,0,0)); 123 124 al_draw_bitmap(dot[0].img, dot[0].x, dot[0].y, 0); 125 al_draw_bitmap(dot[1].img, dot[1].x, dot[1].y, 0); 126 al_draw_bitmap(pacman.img, pacman.x, pacman.y, 0); 127 128 // draw a rectangle around our objects, color them red if that object is colliding 129 if(pacman.collision) 130 al_draw_rectangle(pacman.x, pacman.y, pacman.x+al_get_bitmap_width(pacman.img), pacman.y+al_get_bitmap_height(pacman.img), 131 al_map_rgb(255,0,0), 1.0); 132 else 133 al_draw_rectangle(pacman.x, pacman.y, pacman.x+al_get_bitmap_width(pacman.img), pacman.y+al_get_bitmap_height(pacman.img), 134 al_map_rgb(0,255,0), 1.0); 135 136 for(int i=0; i<=1; i++) { 137 if(dot[i].collision) 138 al_draw_rectangle(dot[i].x, dot[i].y, dot[i].x+al_get_bitmap_width(dot[i].img), dot[i].y+al_get_bitmap_height(dot[i].img), 139 al_map_rgb(255,0,0), 1.0); 140 else 141 al_draw_rectangle(dot[i].x, dot[i].y, dot[i].x+al_get_bitmap_width(dot[i].img), dot[i].y+al_get_bitmap_height(dot[i].img), 142 al_map_rgb(0,255,0), 1.0); 143 } 144 145 al_flip_display(); 146 } 147 } 148 149 // clean up and exit 150 if(pacman.img != NULL) al_destroy_bitmap(pacman.img); 151 if(dot[0].img != NULL) al_destroy_bitmap(dot[0].img); 152 if(dot[1].img != NULL) al_destroy_bitmap(dot[1].img); 153 al_destroy_event_queue(queue); 154 155 return 0; 156}

sprite_collide.c
~~~~~~~~~~~~~~~~

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_color.h> 3#include <allegro5/allegro_primitives.h> 4 5#include "sprite.h" 6#include "sprite_collide.h" 7 8 9// Pixel Perfect collision detector 10int sprite_collide(sprite *object1, sprite *object2) 11{ 12 int left1, left2, over_left; 13 int right1, right2, over_right; 14 int top1, top2, over_top; 15 int bottom1, bottom2, over_bottom; 16 int over_width, over_height; 17 int cx, cy; 18 ALLEGRO_COLOR colour; // Hey, I'm canadian, it's COLOUR here! ;) 19 RGB pixel1, pixel2; 20 int sum1, sum2; 21 22 left1 = object1->x; 23 left2 = object2->x; 24 right1 = object1->x + al_get_bitmap_width(object1->img); 25 right2 = object2->x + al_get_bitmap_width(object2->img); 26 top1 = object1->y; 27 top2 = object2->y; 28 bottom1 = object1->y + al_get_bitmap_height(object1->img); 29 bottom2 = object2->y + al_get_bitmap_height(object2->img); 30 31 32 // First we'll test if the bounding boxes overlap. 33 // If they don't overlap at all, there's no sense in checking further. 34 if(bottom1 < top2) return(FALSE); 35 if(top1 > bottom2) return(FALSE); 36 37 if(right1 < left2) return(FALSE); 38 if(left1 > right2) return(FALSE); 39 40 41 // The bounding boxes overlap, so there's a potential collision. 42 // We'll store the location of the actual overlap 43 if(bottom1 > bottom2) over_bottom = bottom2; 44 else over_bottom = bottom1; 45 46 if(top1 < top2) over_top = top2; 47 else over_top = top1; 48 49 if(right1 > right2) over_right = right2; 50 else over_right = right1; 51 52 if(left1 < left2) over_left = left2; 53 else over_left = left1; 54 55 over_height = over_bottom - over_top; 56 over_width = over_right - over_left; 57 58 // Okay, we found where the overlap occured and we'll now only check within that area for any 59 // collisions. 60 for(cy=0; cy < over_height; cy++) 61 { 62 for(cx=0; cx < over_width; cx++) 63 { 64 // sample a pixel from each object 65 colour = al_get_pixel(object1->img, (over_left-object1->x)+cx, (over_top-object1->y)+cy); 66 al_unmap_rgb(colour, &pixel1.r, &pixel1.g, &pixel1.b); 67 sum1 = pixel1.r+pixel1.g+pixel1.b; 68 69 colour = al_get_pixel(object2->img, (over_left-object2->x)+cx, (over_top-object2->y)+cy); 70 al_unmap_rgb(colour, &pixel2.r, &pixel2.g, &pixel2.b); 71 sum2 = pixel2.r+pixel2.g+pixel2.b; 72 73 // We need to check if the pixel color DOESN'T equal zero, not just greater than zero because 74 // with 32bit color you're going to get negative values in the color information due to the 75 // large size of the number that represents the three colors. 76 // If neither of the two pixels are transparent (black = RGB =0) than we have a collision, 77 // flag it and exit. 78 if((sum1 != 0) && (sum2 != 0)) return(TRUE); 79 } 80 } 81 82 // couldn't find any collision in the overlap 83 return(FALSE); 84}

sprite.h
~~~~~~~~

#SelectExpand
1#ifndef sprite_h 2#define sprite_h 3 4#include <allegro5/allegro.h> 5 6typedef struct sprite 7{ 8 ALLEGRO_BITMAP *img; 9 int x; 10 int y; 11 short int collision; 12 int col_x; 13 int col_y; 14 int col_w; 15 int col_h; 16} sprite; 17 18#endif

sprite_collide.h
~~~~~~~~~~~~~~~~

#ifndef sprite_collide_h
#define sprite_collide_h

typedef struct RGB {
   unsigned char r;
   unsigned char g;
   unsigned char b;
} RGB;

int sprite_collide(sprite *object1, sprite *object2);

#endif

al_error.c
~~~~~~~~~~

// Allegro 5 error message

#include <stdio.h>
#include <allegro5/allegro_native_dialog.h>
#include "al_error.h"

void al_error(const char *func, int line, ALLEGRO_DISPLAY *display, const char *message)
{
   char text[256];

   sprintf(text, "%s(%d): %s", func, line, message);
   al_show_native_message_box(display, "Error", NULL, text,
                              NULL, ALLEGRO_MESSAGEBOX_ERROR);
}

al_error.h
~~~~~~~~~~

#ifndef _al_error_h_
#define _al_error_h_

// usage: error(AT, display, "your message here");
#define AT __func__,__LINE__
   void al_error(const char *func, int line, ALLEGRO_DISPLAY *display, const char *message);

#endif

And the two bitmaps I use:
dot.png: 603494

pacman.png: 603495

There, that's everything. :)

Now I'll try out your suggestions. I'm using this as a test project to basically get the hang of programming Allegro 5 before I do anything major.

EDIT: note some comments were left in from allegro 4 and no longer apply. Like testing the pixels in each bitmap, I now just add up the R G B values together and test, the transparent colour is black so if there is no pixels other than black, the colour will still be zero. I am sure this could be done better, but it was changed from allegro 4 on the fly. Also wouldn't mind speeding the code up where it checks the overlap.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Outside of your for loops where you get the pixel values with al_get_pixel, you should lock both of your sprite bitmaps with al_lock_bitmap(sprite1->img , ALLEGRO_LOCK_READONLY , al_get_bitmap_format(sprite1->img) , 0);. That should speed up access to the data. Access to video memory is slow, so that may be your problem, but on the other hand it might slow you down your drawing to use memory bitmaps instead. Don't forget to al_unlock_bitmap when you're done reading pixels.

Edit -
If you compare the ALLEGRO_COLOR that you get from al_get_pixel to al_map_rgba(0,0,0,0) it would probably be faster than decomposing the color components. Just declare

ALLEGRO_COLOR trans = al_map_rgba(0,0,0,0);

outside your for loops.

Neil Roy
Member #2,229
April 2002
avatar

How can I compare the ALLEGRO_COLORs?

I changed pixel1 so that they are ALLEGRO_COLOR and then...

if (pixel1 != trans)

but you can't do that.

"\sprite_collide.c|70|error: invalid operands to binary != (have 'ALLEGRO_COLOR' and 'ALLEGRO_COLOR')|"

or did I misunderstand?

I changed it to:

  for(cy=0; cy < over_height; cy++) {
      for(cx=0; cx < over_width; cx++) {
         // sample a pixel from each object
         pixel1 = al_get_pixel(object1->img, (over_left-object1->x)+cx, (over_top-object1->y)+cy);

         pixel2 = al_get_pixel(object2->img, (over_left-object2->x)+cx, (over_top-object2->y)+cy);

         // compare the two pixels.  BOTH have to contain a colour other than black (transparent)
         // for a collision to be flaged.  IF either pixel is transparnet than no collision is present.
         if((pixel1 != trans) && (pixel2 != trans)) return true;
      }
   }

Edgar Reynaldo
Member #8,592
May 2007
avatar

Neil Roy said:

I changed pixel1 so that they are ALLEGRO_COLOR and then...

if (pixel1 != trans)

but you can't do that.

Seriously, you can't do that? ??? ALLEGRO_COLOR is just a struct, it should just do a member by member comparison.

I tried it myself, and you're right, it doesn't work. Sorry. :-/

Matthew Leverton
Supreme Loser
January 1999
avatar

If you lock the images with the same int32 format, you could directly compare their values in memory:

((uint32_t *)lock1->data)[x] != ((uint32_t *)lock2->data)[x]

// or 
trans = 0xff000000; /* whatever it is */
((uint32_t *)lock1->data)[x] != trans

Note that the data pointer points to the beginning of image memory, so you would also have to add (y * lock->pitch) to it.

Neil Roy
Member #2,229
April 2002
avatar

I changed the collision detector so it locks the bitmaps and still adds up the values, but after looking at the struct for ALLEGRO_COLOR I see it has rgba values in it, so that saves a step.

It is running very smooth now, no lags. I suspect locking the bitmaps done it.

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_color.h> 3#include <allegro5/allegro_primitives.h> 4 5#include "sprite.h" 6#include "sprite_collide.h" 7 8 9// Pixel Perfect collision detector 10int sprite_collide(sprite *object1, sprite *object2) { 11 int left1, left2, over_left; 12 int right1, right2, over_right; 13 int top1, top2, over_top; 14 int bottom1, bottom2, over_bottom; 15 int over_width, over_height; 16 int cx, cy; 17 ALLEGRO_COLOR pixel[2]; 18 int sum[2]; 19 20 left1 = object1->x; 21 left2 = object2->x; 22 right1 = object1->x + al_get_bitmap_width(object1->img); 23 right2 = object2->x + al_get_bitmap_width(object2->img); 24 top1 = object1->y; 25 top2 = object2->y; 26 bottom1 = object1->y + al_get_bitmap_height(object1->img); 27 bottom2 = object2->y + al_get_bitmap_height(object2->img); 28 29 30 // First we'll test if the bounding boxes overlap. 31 // If they don't overlap at all, there's no sense in checking further. 32 if(bottom1 < top2) return(FALSE); 33 if(top1 > bottom2) return(FALSE); 34 35 if(right1 < left2) return(FALSE); 36 if(left1 > right2) return(FALSE); 37 38 39 // The bounding boxes overlap, so there's a potential collision. 40 // We'll store the location of the actual overlap 41 if(bottom1 > bottom2) over_bottom = bottom2; 42 else over_bottom = bottom1; 43 44 if(top1 < top2) over_top = top2; 45 else over_top = top1; 46 47 if(right1 > right2) over_right = right2; 48 else over_right = right1; 49 50 if(left1 < left2) over_left = left2; 51 else over_left = left1; 52 53 over_height = over_bottom - over_top; 54 over_width = over_right - over_left; 55 56 al_lock_bitmap(object1->img , al_get_bitmap_format(object1->img) , ALLEGRO_LOCK_READONLY); 57 al_lock_bitmap(object2->img , al_get_bitmap_format(object2->img) , ALLEGRO_LOCK_READONLY); 58 // Okay, we found where the overlap occured and we'll now only check within that area for any 59 // collisions. 60 for(cy=0; cy < over_height; cy++) { 61 for(cx=0; cx < over_width; cx++) { 62 // sample a pixel from each object 63 pixel[0] = al_get_pixel(object1->img, (over_left-object1->x)+cx, (over_top-object1->y)+cy); 64 sum[0] = pixel[0].r + pixel[0].g + pixel[0].b; 65 66 pixel[1] = al_get_pixel(object2->img, (over_left-object2->x)+cx, (over_top-object2->y)+cy); 67 sum[1] = pixel[1].r + pixel[1].g + pixel[1].b; 68 69 // the sum of each pixel's RGB components is added together and compared to zero. 70 // the sum of either pixel equals zero than there is no collision. If both pixels 71 // have positive sums than a colour exists and we have a collision. 72 if((sum[0] != 0) && (sum[1] != 0)) return true; 73 } 74 } 75 76 // couldn't find any collision in the overlap 77 return false; 78}

Hmmm, I just realized that a simpler
if (sum[0] && sum[1]) return true;
would do. ;)

Edgar Reynaldo
Member #8,592
May 2007
avatar

Neil Roy
Member #2,229
April 2002
avatar

Yeah, I'll do that... although it didn't seem to effect the program.

Also, I noticed that my adding of sums wasn't 100% effective, it didn't detect all collisions, I changed it to:

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_color.h> 3#include <allegro5/allegro_primitives.h> 4 5#include "sprite.h" 6#include "sprite_collide.h" 7#include "al_error.h" 8 9// Pixel Perfect collision detector 10int sprite_collide(sprite *object1, sprite *object2) 11{ 12 int left1, left2, over_left; 13 int right1, right2, over_right; 14 int top1, top2, over_top; 15 int bottom1, bottom2, over_bottom; 16 int over_width, over_height; 17 int cx, cy; 18 ALLEGRO_COLOR pixel[2]; 19 ALLEGRO_COLOR trans = al_map_rgba(0,0,0,0); 20 bool collision = false; 21 22 left1 = object1->x; 23 left2 = object2->x; 24 right1 = object1->x + al_get_bitmap_width(object1->img); 25 right2 = object2->x + al_get_bitmap_width(object2->img); 26 top1 = object1->y; 27 top2 = object2->y; 28 bottom1 = object1->y + al_get_bitmap_height(object1->img); 29 bottom2 = object2->y + al_get_bitmap_height(object2->img); 30 31 32 // First we'll test if the bounding boxes overlap. 33 // If they don't overlap at all, there's no sense in checking further. 34 if(bottom1 < top2) return(FALSE); 35 if(top1 > bottom2) return(FALSE); 36 37 if(right1 < left2) return(FALSE); 38 if(left1 > right2) return(FALSE); 39 40 41 // The bounding boxes overlap, so there's a potential collision. 42 // We'll store the location of the actual overlap 43 if(bottom1 > bottom2) over_bottom = bottom2; 44 else over_bottom = bottom1; 45 46 if(top1 < top2) over_top = top2; 47 else over_top = top1; 48 49 if(right1 > right2) over_right = right2; 50 else over_right = right1; 51 52 if(left1 < left2) over_left = left2; 53 else over_left = left1; 54 55 over_height = over_bottom - over_top; 56 over_width = over_right - over_left; 57 58 al_lock_bitmap(object1->img , al_get_bitmap_format(object1->img) , ALLEGRO_LOCK_READONLY); 59 al_lock_bitmap(object2->img , al_get_bitmap_format(object2->img) , ALLEGRO_LOCK_READONLY); 60 // Okay, we found where the overlap occured and we'll now only check within that area for any 61 // collisions. 62 for(cy=0; cy < over_height; cy++) 63 { 64 for(cx=0; cx < over_width; cx++) 65 { 66 // sample a pixel from each object 67 pixel[0] = al_get_pixel(object1->img, (over_left-object1->x)+cx, (over_top-object1->y)+cy); 68 pixel[1] = al_get_pixel(object2->img, (over_left-object2->x)+cx, (over_top-object2->y)+cy); 69 70 71 if(memcmp(&pixel[0], &trans, sizeof(trans)) && memcmp(&pixel[1], &trans, sizeof(trans))) 72 { 73 collision=true; 74 break; 75 } 76 } 77 if(collision) break; 78 } 79 80 al_unlock_bitmap(object1->img); 81 al_unlock_bitmap(object2->img); 82 83 return collision; 84}

Which now works perfectly and detects them fine, and skips the step of adding them up which is probably an improvement.

Edit: I notice a tiny hiccup of a lag... not much, but still... I'll keep working on this, and try and implement your ideas for comparing the colours.

Edit2: I wonder if a simple memcmp() would do the trick?

Edit3: Okay, I just tried memcmp() and it seems to work nicely. I don't know if there are any problems with doing it this way, but it seems to be okay.
I updated the code above to show what I have now.

Edit4: Crap, forgot to unlock the bitmaps! ::) <updated>

Go to: