Hello!
Do somebody know how to make collision in allegro? I need help and I'm stuck in my game
I've seen a tutorial about it but it just explained how to print "Collision!" if it was true. I thought It would work if I made some variables that switched true or false if the character was in a specific area but it didn't work out. If you have any idea how I should make it please replay or send any links for tutorials.
Thanks! 
Mrukki
This function might help you:
| 1 | /* |
| 2 | Sprite structure |
| 3 | */ |
| 4 | //SPRITE Structure |
| 5 | typedef struct SPRITE |
| 6 | { |
| 7 | //Supported elements |
| 8 | int dir, alive; |
| 9 | |
| 10 | //Main Elements |
| 11 | int x,y; |
| 12 | int width, height; |
| 13 | int xspeed, yspeed; |
| 14 | int xdelay, ydelay; |
| 15 | int xcount, ycount; |
| 16 | int curframe, maxframe, animdir; |
| 17 | int framecount, framedelay; |
| 18 | }SPRITE; |
| 19 | |
| 20 | /* |
| 21 | Check if both sprites are inside each other or touching |
| 22 | */ |
| 23 | //Inside Function |
| 24 | bool Y_YInside(int x,int y,int left,int top,int right,int bottom) |
| 25 | { |
| 26 | if(x > left && x < right && y > top && y < bottom) |
| 27 | {return true;} |
| 28 | |
| 29 | return false; |
| 30 | } |
| 31 | |
| 32 | /* |
| 33 | This is the main fuction that you are going to use |
| 34 | with this you will know if collition was alive. |
| 35 | |
| 36 | This fuction returns true if collition is made. |
| 37 | This fuction will return false if collition is not made. |
| 38 | */ |
| 39 | |
| 40 | //Collition test |
| 41 | bool Y_YCollide(SPRITE *a,SPRITE *b) |
| 42 | { |
| 43 | int wa = a->x + a->width; |
| 44 | int ha = a->y + a->height; |
| 45 | int wb = b->x + b->width; |
| 46 | int hb = b->y + b->height; |
| 47 | int bx = 5; |
| 48 | int by = 5; |
| 49 | |
| 50 | if(Y_YInside(a->x, a->y, b->x+bx, b->y+by, wb-bx,hb-by) || |
| 51 | Y_YInside(a->x, ha, b->x+bx, b->y+by, wb-bx, hb-by) || |
| 52 | Y_YInside(wa, a->y, b->x+bx, b->y+by, wb-bx, hb-by) || |
| 53 | Y_YInside(wa, ha, b->x+bx, b->y+by, wb-bx, hb-by)) |
| 54 | { |
| 55 | return true; |
| 56 | } |
| 57 | |
| 58 | return false; |
| 59 | } |
Yellow_Yackets: please use [code]...[/code] tags...
mrukki: for collision detection, tell us what kinds of objects you already have. You should both their x/y coordinates and their height/width. You can do rectangular bounds checking (not extremely accurate, but good enough), circular bounds checking (a little more accurate), etc.
For rectangular bounds checking, use Yellow_Yackets' suggestion. For circular, simply determine on both objects where you want to ensure that they collide, and then use the distance formula (sqrt(a^2 + b^2)) and check that they don't. (More accurately: sqrt[(obj1.x - obj2.x)^2 + (obj1.y - obj2.y)^2].)
Thanks guys! Now I have one idea!
I'm going to make variables for the characters top, bottom, left and right and a function for the other objects with the same idea.
Then I'm going to check if the characters bottom value is smaller then the objects top value and if true it can walk and the same idea for all sides
But then the character can't pass the top value of the objects, like if I want to go on the right side of the character. How should I do that?
inline bool collide(int x1, int y1, int x2, int y2, int xx1, int yy1, int xx2, int yy2) { if (x2 <= xx1) return false; else if (x1 >= xx2) return false; else if (y2 <= yy1) return false; else if (y1 >= yy2) return false; else return true; }
Tags: Bounding Box Collision
A suggestion if you want to go with circular collisions as TeamTerradactyl suggested
Don't use sqrt(), it can become a bottle neck for the code, instead of taking the square root of the two squares, square what you are comparing it to.
(distance ^ 2) < (a^2 + b^2)
and save on the sqrt() call, also ^ in c/c++ is the xor operator, not power of, so you will have to go
(distance * distance) < ((a * a) + (b * b))
-Tim
Timorg: Thanks, but I'm using cub like players 
Paul whoknows: Thanks, I understand but not how I should use it? I have 4 variables called walk_u, walk_d, walk_r and walk_l, and I switching them true or false. How can I switch those when I use the function? Can I return the variables?
One way is to check an objects future position with the bounding box collision check Paul suggested. That is , if they try to move , find their future position and check it with the bounding box collision function. If there is a collision , then they can't move that direction so don't update their position. However , If an object moves more that it's width combined with another object's width , then it can skip over the object in front of it using this method.
Thanks! Pauls function works good but it can't return 3 
This is my code:
inline bool collide(int x1, int y1, int x2, int y2, int xx1, int yy1, int xx2, int yy2) { if (x2 >= xx1) return 0; else if (x2 < xx1) return 1; else if (x1 >= xx2) return false; else if (y2 <= yy1) return false; else if (y1 >= yy2) return false; } if (collide(image1_bb_left, image1_bb_top, image1_bb_right, image1_bb_bottom, image2_bb_left, image2_bb_top, image2_bb_right, image2_bb_bottom) == 0) walk_r = false; else if (collide(image1_bb_left, image1_bb_top, image1_bb_right, image1_bb_bottom, image2_bb_left, image2_bb_top, image2_bb_right, image2_bb_bottom) == 1) walk_r = true;
thats works good but if I do another statement in the function that I want to return 3 or change 1 to 3 it doesn't work
Depending on what you want to do when a collision happens , if you just want to prevent the player from moving , then this would work fine.
| 1 | bool moveleft = false; |
| 2 | bool moveright = false; |
| 3 | bool moveup = false; |
| 4 | bool movedown = false; |
| 5 | bool moving = false; |
| 6 | |
| 7 | // player and object positions |
| 8 | int ptlx = 100; |
| 9 | int ptly = 100; |
| 10 | int pbrx = 199; |
| 11 | int pbry = 199; |
| 12 | int otlx = 300; |
| 13 | int otly = 300; |
| 14 | int obrx = 349; |
| 15 | int obry = 349; |
| 16 | |
| 17 | const int v = 5;// player x and y velocity when moving |
| 18 | int pvx = 0; |
| 19 | int pvy = 0; |
| 20 | |
| 21 | while (playing_game) { |
| 22 | if (key[KEY_LEFT]) {moveleft = true;} else {moveleft = false;} |
| 23 | if (key[KEY_RIGHT]) {moveright = true;} else {moveright = false;} |
| 24 | if (key[KEY_UP]) {moveup = true;} else {moveup = false;} |
| 25 | if (key[KEY_DOWN]) {movedown = true;} else {movedown = false;} |
| 26 | moving = false; |
| 27 | pvx = 0; |
| 28 | pvy = 0; |
| 29 | if (moveright) {pvx = v;moving = true;} |
| 30 | if (moveleft) {pvx = -1*v;moving = true;} |
| 31 | if (moveup) {pvy = -1*v;moving = true;} |
| 32 | if (movedown) {pvy = v;moving = true;} |
| 33 | if (moving) { |
| 34 | if (collide(ptlx + pvx , ptly + pvy , pbrx + pvx , pbry + pvy , otlx , otly , obrx , obry)) { |
| 35 | moving = false; |
| 36 | } |
| 37 | } |
| 38 | if (moving) {// if moving the player would not cause a collision , move the player and update the screen |
| 39 | ptlx += pvx; |
| 40 | ptly += pvy; |
| 41 | pbrx += pvx; |
| 42 | pbry += pvy; |
| 43 | update_screen(); |
| 44 | } |
| 45 | } |
However if you'd like to know which side it collided on , since it can only collide on the sides that it was moving towards , then check for overlaps in those directions.
Altering the previous code would give :
| 1 | bool moveleft = false; |
| 2 | bool moveright = false; |
| 3 | bool moveup = false; |
| 4 | bool movedown = false; |
| 5 | bool moving = false; |
| 6 | |
| 7 | bool collidedonleft = false; |
| 8 | bool collidedonright = false; |
| 9 | bool collidedontop = false; |
| 10 | bool collidedonbottom = false; |
| 11 | |
| 12 | // player and object positions |
| 13 | int ptlx = 100; |
| 14 | int ptly = 100; |
| 15 | int pbrx = 199; |
| 16 | int pbry = 199; |
| 17 | int otlx = 300; |
| 18 | int otly = 300; |
| 19 | int obrx = 349; |
| 20 | int obry = 349; |
| 21 | |
| 22 | const int v = 5;// player x and y velocity when moving |
| 23 | int pvx = 0; |
| 24 | int pvy = 0; |
| 25 | |
| 26 | while (playing_game) { |
| 27 | if (key[KEY_LEFT]) {moveleft = true;} else {moveleft = false;} |
| 28 | if (key[KEY_RIGHT]) {moveright = true;} else {moveright = false;} |
| 29 | if (key[KEY_UP]) {moveup = true;} else {moveup = false;} |
| 30 | if (key[KEY_DOWN]) {movedown = true;} else {movedown = false;} |
| 31 | moving = false; |
| 32 | pvx = 0; |
| 33 | pvy = 0; |
| 34 | if (moveright) {pvx = v;moving = true;} |
| 35 | if (moveleft) {pvx = -1*v;moving = true;} |
| 36 | if (moveup) {pvy = -1*v;moving = true;} |
| 37 | if (movedown) {pvy = v;moving = true;} |
| 38 | if (moving) { |
| 39 | if (collide(ptlx + pvx , ptly + pvy , pbrx + pvx , pbry + pvy , otlx , otly , obrx , obry)) { |
| 40 | moving = false; |
| 41 | // find out which side collision happened on |
| 42 | collidedonright = collidedonleft = collidedontop = collidedonbottom = false; |
| 43 | if (moveright) {if (pbrx + pvx >= otlx) {collidedonright = true;} |
| 44 | if (moveleft) {if (ptlx + pvx <= obrx) {collidedonleft = true;} |
| 45 | if (moveup) {if (ptly + pvy <= obry) {collidedontop = true;} |
| 46 | if (movedown) {if (pbry + pvy >= otly) {collidedonbottom = true;} |
| 47 | } |
| 48 | } |
| 49 | if (moving) {// if moving the player would not cause a collision , move the player and update the screen |
| 50 | ptlx += pvx; |
| 51 | ptly += pvy; |
| 52 | pbrx += pvx; |
| 53 | pbry += pvy; |
| 54 | update_screen(); |
| 55 | } |
| 56 | } |
YES!!! I made it!! I used Pauls idea to make those functions.
This is my code:
| 1 | inline bool collide_r(int t1, int b1, int r1, int l1, int t2, int b2, int r2, int l2) |
| 2 | { |
| 3 | if (r1 == l2 && b1 > t2 && t1 < b2) return false; |
| 4 | else return true; |
| 5 | } |
| 6 | |
| 7 | inline bool collide_l(int t1, int b1, int r1, int l1, int t2, int b2, int r2, int l2) |
| 8 | { |
| 9 | if (l1 == r2 && b1 > t2 && t1 < b2) return false; |
| 10 | else return true; |
| 11 | } |
| 12 | |
| 13 | inline bool collide_t(int t1, int b1, int r1, int l1, int t2, int b2, int r2, int l2) |
| 14 | { |
| 15 | if (b1 == t2 && r1 > l2 && l1 < r2) return false; |
| 16 | else return true; |
| 17 | } |
| 18 | |
| 19 | inline bool collide_b(int t1, int b1, int r1, int l1, int t2, int b2, int r2, int l2) |
| 20 | { |
| 21 | if (t1 == b2 && r1 > l2 && l1 < r2) return false; |
| 22 | else return true; |
| 23 | } |
Thanks everybody! Now I can continue working on my game!
Your code for the collide_r function :
inline bool collide_r(int t1, int b1, int r1, int l1, int t2, int b2, int r2, int l2) { if (r1 == l2 && b1 > t2 && t1 < b2) return false; else return true; }
Semantically , that code is :
"If
(the right edge of object 1 is in the same place as the left edge of object 2) and (the bottom edge of object 1 is lower than the top edge of object 2) and
(the top edge of object 1 is higher than the bottom edge of object 2)
then no collision occurred , otherwise a collision occurred."
First of all , that will only work if you only ever move your objects by one at a time. Second , I think you've reversed the value that is returned by it. If all three of the conditions are true then a collision has occurred (The edges are at the same position and their dimensions perpendicular to the direction of movement overlap (collide_r is for when moving right , correct?)) but you return false.
Dang, mrukki, that sure is complicated.
Why have all those separate functions (and all those passed-in variables)?!
| 1 | enum Collisions |
| 2 | { |
| 3 | COLLISION_NONE, COLLISION_TOP, COLLISION_RIGHT, COLLISION_BOTTOM, COLLISION_LEFT |
| 4 | }; |
| 5 | |
| 6 | struct Objects |
| 7 | { |
| 8 | int x, y; // The center of the object |
| 9 | int top, left, right, bottom; // In other words, x1, y1, x2, y2 |
| 10 | BITMAP *image; |
| 11 | }; |
| 12 | |
| 13 | int collide_rect(Objects &player1, Objects &player2) |
| 14 | { |
| 15 | int result = COLLISION_NONE; |
| 16 | |
| 17 | // Check if ANY collision has occured |
| 18 | if ((player1.left > player2.right) || (player2.left > player1.right) || |
| 19 | (player1.top > player2.bottom) || (player2.top > player1.bottom)) |
| 20 | { |
| 21 | // The two players are not overlapping in any way, so exit early |
| 22 | return result; |
| 23 | } |
| 24 | |
| 25 | // A collision occurred. Now, determine where it happened... |
| 26 | if (...) |
| 27 | |
| 28 | // ... |
| 29 | |
| 30 | return result; |
| 31 | } |
This should tell you where the collision hit (by the returned "Collisions" value), and if it returns "none", then you don't have to do any further tests.
Having the structure such that you represent the x/y coordinates (as being the center of the image), you can even use the same structure to do rounded bounds checking (which can be even faster than rectangular bounds checking).
Edgar Reynaldo: I have variables called walk_r, walk_l, walk_u and walk_d and if a collision occurred it turns to false and ex walk_r turns false.
OnlineCop: Thanks!
I knew that I could made it esier but not that easy! 
I've tried to use OnlineCops function but I getting errors
This is my code:
if (collide_rect(image1, image2) == COLLISION_NONE) { walk_u = true; walk_d = true; walk_l = true; walk_r = true; }
And I get the error: invalid initialization of reference of type 'Objects&' from expression of type 'BITMAP*' in passing argument 1 of `int collide_rect(Objects&, Objects&)'
I don't understand the error but it's something with image1 and image2,
How should I do?
Are you passing a BITMAP* to the function, instead of an object? Here is an example of how to use it if you are:
| 1 | Objects object1,object2; |
| 2 | //set up object1 |
| 3 | object1.left = 20; |
| 4 | object1.right = 40; |
| 5 | object1.top = 50; |
| 6 | object1.bottom = 80; |
| 7 | object1.image = image1; //assuming that image1 is the bitmap you loaded |
| 8 | |
| 9 | //set up object2 |
| 10 | object2.left = 30; |
| 11 | object2.right = 55; |
| 12 | object2.top = 40; |
| 13 | object2.bottom = 70; |
| 14 | object2.image = image2; |
| 15 | |
| 16 | if (collide_rect(object1, object2) == COLLISION_NONE) |
| 17 | { |
| 18 | walk_u = true; |
| 19 | walk_d = true; |
| 20 | walk_l = true; |
| 21 | walk_r = true; |
| 22 | } |
Hope this helps;D.
Oh yeah! Thanks man!
I'll try this right away! 
EDITED: OH!! Why won't it work! I've tried all ways but it just don't work!
I used your functions and came up to this:
| 1 | enum Collisions |
| 2 | { |
| 3 | COLLISION_NONE, COLLISION_TOP, COLLISION_RIGHT, COLLISION_BOTTOM, COLLISION_LEFT |
| 4 | }; |
| 5 | |
| 6 | struct Objects |
| 7 | { |
| 8 | int x, y; // The center of the object |
| 9 | int top, left, right, bottom; // In other words, x1, y1, x2, y2 |
| 10 | BITMAP *image; |
| 11 | }; |
| 12 | |
| 13 | int collide_rect(Objects &player1, Objects &player2) |
| 14 | { |
| 15 | int result = COLLISION_NONE; |
| 16 | int right = COLLISION_RIGHT; |
| 17 | int left = COLLISION_LEFT; |
| 18 | int top = COLLISION_TOP; |
| 19 | int bottom = COLLISION_BOTTOM; |
| 20 | |
| 21 | if ((player1.left > player2.right) || (player2.left > player1.right) || |
| 22 | (player1.top > player2.bottom) || (player2.top > player1.bottom)) |
| 23 | { |
| 24 | return result; |
| 25 | } |
| 26 | |
| 27 | if (player1.right == player2.left) |
| 28 | return right; |
| 29 | |
| 30 | if (player1.left == player2.right) |
| 31 | return left; |
| 32 | |
| 33 | if ((player1.bottom == player2.top) |
| 34 | return bottom; |
| 35 | |
| 36 | if (player1.top == player2.bottom) |
| 37 | return top; |
| 38 | } |
| 39 | |
| 40 | //------------------------------------- |
| 41 | |
| 42 | int charx = 0; |
| 43 | int chary = 0; |
| 44 | |
| 45 | int l1 = charx; |
| 46 | int t1 = chary; |
| 47 | |
| 48 | int r1 = (l1 + image1->w); |
| 49 | int b1 = (t1 + image1->h); |
| 50 | |
| 51 | int l2 = 100; |
| 52 | int t2 = 100; |
| 53 | |
| 54 | int r2 = (l2 + image2->w); |
| 55 | int b2 = (t2 + image2->h); |
| 56 | |
| 57 | Objects object1,object2; |
| 58 | |
| 59 | object1.left = l1; |
| 60 | object1.right = r1; |
| 61 | object1.top = t1; |
| 62 | object1.bottom = b1; |
| 63 | object1.image = image1; |
| 64 | |
| 65 | object2.left = l2; |
| 66 | object2.right = r2; |
| 67 | object2.top = t2; |
| 68 | object2.bottom = b2; |
| 69 | object2.image = image2; |
| 70 | |
| 71 | //---------------------------------------------------- |
| 72 | |
| 73 | if (collide_rect(object1, object2) == COLLISION_TOP) |
| 74 | walk_u = false; |
| 75 | |
| 76 | if (collide_rect(object1, object2) == COLLISION_BOTTOM) |
| 77 | walk_d = false; |
| 78 | |
| 79 | if (collide_rect(object1, object2) == COLLISION_RIGHT) |
| 80 | walk_r = false; |
| 81 | |
| 82 | if (collide_rect(object1, object2) == COLLISION_LEFT) |
| 83 | walk_l = false; |
| 84 | walk_r = true; |
| 85 | |
| 86 | if (collide_rect(object1, object2) == COLLISION_NONE) |
| 87 | { |
| 88 | walk_u = true; |
| 89 | walk_d = true; |
| 90 | walk_l = true; |
| 91 | walk_r = true; |
| 92 | } |
And when I get in collision it just ignore it, I don't know how to do?
Please help me!
You don't need the lines:
int right = COLLISION_RIGHT; int left = COLLISION_LEFT; int top = COLLISION_TOP; int bottom = COLLISION_BOTTOM;
I've reworked this (haven't tested it, but logically, it should work...), but try something like this:
| 1 | enum Collisions |
| 2 | { |
| 3 | COLLISION_NONE, |
| 4 | COLLISION_TOPL, COLLISION_TOPR, // top-left and top-right |
| 5 | COLLISION_BOTTOML, COLLISION_BOTTOMR // bottom-left and bottom-right |
| 6 | }; |
| 7 | |
| 8 | struct Objects |
| 9 | { |
| 10 | int x, y; // The center of the object |
| 11 | int top, left, right, bottom; // In other words, x1, y1, x2, y2 |
| 12 | BITMAP *image; |
| 13 | }; |
| 14 | |
| 15 | int collide_rect(Objects &player1, Objects &player2) |
| 16 | { |
| 17 | int result = COLLISION_NONE; |
| 18 | |
| 19 | if ((player1.left > player2.right) || (player2.left > player1.right) || |
| 20 | (player1.top > player2.bottom) || (player2.top > player1.bottom)) |
| 21 | { |
| 22 | return result; |
| 23 | } |
| 24 | |
| 25 | |
| 26 | // To simplify testing, create an array where [0] is always left of [1] |
| 27 | Objects players[2]; |
| 28 | if (player1.x < player2.x) |
| 29 | { |
| 30 | players[0] = player1; |
| 31 | players[1] = player2; |
| 32 | } |
| 33 | else |
| 34 | { |
| 35 | players[0] = player2; |
| 36 | players[1] = player1; |
| 37 | } |
| 38 | |
| 39 | if (players[0].right > players[1].left) |
| 40 | { |
| 41 | // Possible collision on players[0]'s right side and players[1]'s left |
| 42 | |
| 43 | // Now check for vertical collision |
| 44 | if (players[0].bottom > players[1].top) |
| 45 | { |
| 46 | // players[0] collided with players[1]'s top-left |
| 47 | result = COLLISION_TOPL; |
| 48 | } |
| 49 | else if (players[0].top < players[1].bottom) |
| 50 | { |
| 51 | // players[0] collided with players[1]'s bottom-left |
| 52 | result = COLLISION_BOTTOML; |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | // There is no reason to do a test for "collided on the left side" since |
| 57 | // the sorting above accomplished this for us implicitely. |
| 58 | |
| 59 | // We'll need to correctly assign where the collision took place, so now |
| 60 | // test whether players[0] == player1 or player2, and swap accordingly |
| 61 | if ((players[0] == player2) && (result != COLLISION_NONE)) |
| 62 | { |
| 63 | if (result == COLLISION_TOPL) |
| 64 | result = COLLISION_TOPR; |
| 65 | else |
| 66 | result = COLLISION_BOTTOMR; |
| 67 | } |
| 68 | |
| 69 | return result; |
| 70 | } |
It may blow up, but I THINK that it should work now.
Mrukki, in the collision detection code you posted you have the checks as '=='. Ex: if(player1.left == player2.right) This wouldn't always work because player1's left could be past player2's right and still be having a collision.
594280
Try OnlineCop's code, it should work.
OnlineCop: Your code is great! But it have an error
I think this should work!:o
It's in this code thing:
if ((players[0] == player2) && (result != COLLISION_NONE))
Here's the error message:
no match for 'operator==' in 'players[0] == player2'
int operator==(fix, fix)
int operator==(int, fix)
int operator==(fix, long int)
int operator==(long int, fix)
int operator==(fix, float)
int operator==(float, fix)
int operator==(fix, double)
int operator==(double, fix)
It should probably be something like:
if ((players[0] == &player2) && result != COLLISION_NONE))
The "players[0]" should be pointing to the address of player2, instead of to the object itself. See if that helps.
I didn't work. I got the same error
But thanks anyway!
Semantically , there's nothing wrong with the line the way it was when you first got the error. From OnlineCop's code , players[0] and player2 are both 'Objects' objects. There may be some kind of include error. That's usually the only time I see the compiler suggest allegro's fixed class functions. You may have to actually write an equivalence operator for the Objects class(struct) yourself. I can't remember if the compiler supplies a default equivalence operator or not.
From http://www.cplusplus.com/doc/tutorial/classes.html :
But the compiler not only creates a default constructor for you if you do not specify your own. It provides three special member functions in total that are implicitly declared if you do not declare your own. These are the copy constructor, the copy assignment operator, and the default destructor.
So , no I don't believe the compiler supplies a default equivalence operator.
You could write one like this :
| 1 | struct Objects |
| 2 | { |
| 3 | int x, y; // The center of the object |
| 4 | int top, left, right, bottom; // In other words, x1, y1, x2, y2 |
| 5 | BITMAP *image; |
| 6 | |
| 7 | // pick one of the following two methods |
| 8 | |
| 9 | // to check if all the members are equivalent |
| 10 | bool operator==(const Objects& rightside) { |
| 11 | if (x != rightside.x) {return false;} |
| 12 | if (y != rightside.y) {return false;} |
| 13 | if (top != rightside.top) {return false;} |
| 14 | if (left != rightside.left) {return false;} |
| 15 | if (right != rightside.right) {return false;} |
| 16 | if (bottom != rightside.bottom) {return false;} |
| 17 | if (image != rightside.image) {return false;} |
| 18 | |
| 19 | return true; |
| 20 | } |
| 21 | // or use this version to see if they are in fact the same object (same position in memory) |
| 22 | bool operator==(const Objects& rightside) { |
| 23 | if (this == &rightside) {return true;} |
| 24 | return false; |
| 25 | } |
| 26 | }; |
However , you could accomplish the same thing in OnlineCop's code by making players[2] an array of two pointers to player1 and player2 instead. You can only do that as long as the function parameters are Objects& (Objects references) though.
So you would use these kind of things instead :
| 1 | Objects* players[2]; |
| 2 | if (player1.x < player2.x) { |
| 3 | players[0] = &player1; |
| 4 | players[1] = &player2; |
| 5 | } else { |
| 6 | players[0] = &player2; |
| 7 | players[1] = &player1; |
| 8 | } |
| 9 | // but now you have to use the -> (dereference) operator instead of the . (member access) operator to access the data members |
| 10 | if (players[0]->right > players[1]->left) { |
| 11 | // the first pointer to a player , it's player's right edge is right of the |
| 12 | // other player's left edge |
| 13 | } |
| 14 | |
| 15 | |
| 16 | /// And to check if the objects are the same , just compare their addresses |
| 17 | if (players[0] == &player1) {// do stuff} |
Edgar Reynaldo: Thanks for the code but I think it's to difficult
I'm just a noob and I don't want to use code that I don't understand
I'll tried this code but the collision don't work, the character just pass by
What have I done wrong?
| 1 | struct object |
| 2 | { |
| 3 | int left; |
| 4 | int right; |
| 5 | int top; |
| 6 | int bottom; |
| 7 | |
| 8 | BITMAP *image; |
| 9 | }; |
| 10 | |
| 11 | enum |
| 12 | { |
| 13 | collision_left, |
| 14 | collision_top, |
| 15 | collision_right, |
| 16 | collision_bottom, |
| 17 | collision_none |
| 18 | }; |
| 19 | |
| 20 | int box_check(object &obj1, object &obj2) |
| 21 | { |
| 22 | if (obj1.bottom == obj2.top) { return collision_bottom; } |
| 23 | if (obj1.top == obj2.bottom) { return collision_top; } |
| 24 | if (obj1.right == obj2.left) { return collision_right; } |
| 25 | if (obj1.left == obj2.right) { return collision_left; } |
| 26 | else collision_none; |
| 27 | } |
| 28 | |
| 29 | if (box_check(character, tree) == collision_right) |
| 30 | { |
| 31 | walk_r = false; |
| 32 | } |
That will only work if the character moves 1 pixel at a time. Do you remember to update the bottom right corner position values when the character moves?
In my previous post , if the code in the first window is too advanced for right now , the code in the second window was just a very minor modification to what you were using from OnlineCop's code. It was only to prevent the compiler error you were getting by allowing you to check if they were the same objects by checking to see if they had the same address in memory.
I've updating the variables like this:
while (!key[KEY_ESC]) { while (speed > 0) { l1 = charx; t1 = chary; r1 = (l1 + image1->w); b1 = (t1 + image1->h); character.left = l1; character.right = r1; character.top = t1; character.bottom = b1;
Yeah, But I think I'll first try to get my code to work
But thank for the codes I'll look at it and try to understand
Okay , but how are charx and chary updated?
I don't know what's going on. Let's just see all of the code entirely. Upload it as an attachment if you need to and then we can skim through it and see if anything sticks out.
Maybe I see something.
When you call the box_check function , aren't you comparing their current positions instead of the future position of your player against the current position of the object? That would let objects overlap by one , but it shouldn't overlap any further. I don't notice anything else. Let's see the whole file for main() and any character or collision code.
Code!
There's the code!
I hope you or someone else find the error(s) 
Thanks!
I put your code up here because it's easier to refer to and look at with some formatting. There is an attachments button in the post editing area you can upload pictures / code with and then include a link to.
| 1 | #include <allegro.h> |
| 2 | |
| 3 | volatile long speed = 0; |
| 4 | |
| 5 | void increment() |
| 6 | { |
| 7 | speed ++; |
| 8 | }END_OF_FUNCTION(increment); |
| 9 | |
| 10 | struct object |
| 11 | { |
| 12 | int left; |
| 13 | int right; |
| 14 | int top; |
| 15 | int bottom; |
| 16 | BITMAP *image; |
| 17 | }; |
| 18 | |
| 19 | |
| 20 | enum |
| 21 | { |
| 22 | collision_left, |
| 23 | collision_top, |
| 24 | collision_right, |
| 25 | collision_bottom, |
| 26 | collision_none |
| 27 | }; |
| 28 | |
| 29 | int box_check(object &obj1, object &obj2) |
| 30 | { |
| 31 | if (obj1.bottom == obj2.top) { return collision_bottom; } |
| 32 | if (obj1.top == obj2.bottom) { return collision_top; } |
| 33 | if (obj1.right == obj2.left) { return collision_right; } |
| 34 | if (obj1.left == obj2.right) { return collision_left; } |
| 35 | else collision_none; |
| 36 | } |
| 37 | |
| 38 | int main(int argc, char *argv[]) |
| 39 | { |
| 40 | allegro_init(); |
| 41 | install_keyboard(); |
| 42 | install_timer(); |
| 43 | |
| 44 | LOCK_VARIABLE(speed); |
| 45 | LOCK_FUNCTION(increment); |
| 46 | install_int_ex(increment, BPS_TO_TIMER(60)); |
| 47 | |
| 48 | set_color_depth(24); |
| 49 | set_gfx_mode(GFX_AUTODETECT, 400,400,0,0); |
| 50 | |
| 51 | |
| 52 | BITMAP *image1 = load_bitmap("character.bmp", NULL); |
| 53 | BITMAP *image2 = load_bitmap("tree.bmp", NULL); |
| 54 | BITMAP *water = load_bitmap("water.bmp", NULL); |
| 55 | BITMAP *buffer = create_bitmap(400, 400); |
| 56 | |
| 57 | if (image1 == NULL || image2 == NULL || water == NULL || buffer == NULL) |
| 58 | { |
| 59 | set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); |
| 60 | allegro_message("Could not load bitmap!"); |
| 61 | exit(EXIT_FAILURE); |
| 62 | } |
| 63 | |
| 64 | int charx = 0; |
| 65 | int chary = 0; |
| 66 | |
| 67 | int l1 = charx; |
| 68 | int t1 = chary; |
| 69 | |
| 70 | int r1 = (l1 + image1->w); |
| 71 | int b1 = (t1 + image1->h); |
| 72 | |
| 73 | int l2 = 100; |
| 74 | int t2 = 100; |
| 75 | |
| 76 | int r2 = (l2 + image2->w); |
| 77 | int b2 = (t2 + image2->h); |
| 78 | |
| 79 | int l3 = 200; |
| 80 | int t3 = 0; |
| 81 | |
| 82 | int r3 = (l3 + water->w); |
| 83 | int b3 = (t3 + water->h); |
| 84 | |
| 85 | bool walk_d = true; |
| 86 | bool walk_u = true; |
| 87 | bool walk_r = true; |
| 88 | bool walk_l = true; |
| 89 | |
| 90 | object character,tree; |
| 91 | //set up object1 |
| 92 | character.left = l1; |
| 93 | character.right = r1; |
| 94 | character.top = t1; |
| 95 | character.bottom = b1; |
| 96 | character.image = image1; //assuming that image1 is the bitmap you loaded |
| 97 | |
| 98 | //set up object2 |
| 99 | tree.left = l2; |
| 100 | tree.right = r2; |
| 101 | tree.top = t2; |
| 102 | tree.bottom = b2; |
| 103 | tree.image = image2; |
| 104 | |
| 105 | while (!key[KEY_ESC]) |
| 106 | { |
| 107 | while (speed > 0) |
| 108 | { |
| 109 | l1 = charx; |
| 110 | t1 = chary; |
| 111 | |
| 112 | r1 = (l1 + image1->w); |
| 113 | b1 = (t1 + image1->h); |
| 114 | |
| 115 | character.left = l1; |
| 116 | character.right = r1; |
| 117 | character.top = t1; |
| 118 | character.bottom = b1; |
| 119 | //-------------------------------- |
| 120 | if (box_check(character, tree) == collision_none) |
| 121 | { |
| 122 | return 1; |
| 123 | } |
| 124 | //--------------------------------------------- |
| 125 | if (key[KEY_RIGHT] && walk_r == true) |
| 126 | charx ++; |
| 127 | |
| 128 | if (key[KEY_LEFT] && walk_l == true) |
| 129 | charx --; |
| 130 | |
| 131 | if (key[KEY_DOWN] && walk_d == true) |
| 132 | chary ++; |
| 133 | |
| 134 | if (key[KEY_UP] && walk_u == true) |
| 135 | chary --; |
| 136 | |
| 137 | speed --; |
| 138 | } |
| 139 | draw_sprite(buffer, image1, charx, chary); |
| 140 | draw_sprite(buffer, image2, 100, 100); |
| 141 | draw_sprite(buffer, water, 200, 0); |
| 142 | textprintf_ex(buffer, font, 0,0, makecol(255,0,255), -1, "Collision test"); |
| 143 | |
| 144 | blit(buffer, screen, 0, 0, 0, 0, 400, 400); |
| 145 | clear_bitmap(buffer); |
| 146 | } |
| 147 | |
| 148 | destroy_bitmap(buffer); |
| 149 | destroy_bitmap(image1); |
| 150 | destroy_bitmap(image2); |
| 151 | |
| 152 | return 0; |
| 153 | }END_OF_MAIN() |
If you look at the code right around your call to the box_check function :
if (box_check(character, tree) == collision_none) { return 1; }
Why is return 1 there? If there's no collision quit?
But that's besides the point , right around the call to box_check , you never set all your walk_direction variables to true each time through the loop and check to see if they should be false by looking at the value box_check returns.
You should set all four walk_ variables to true each time through the while loop and then use the return value of box_check to decide whether any of those variables should be set to false to prevent movement in that direction.
Oh, I just used that just to test
It should look like this:
if (box_check(character, tree) == collision_none) { walk_u = true; walk_d = true; walk_r = true; walk_l = true; }
Do you mean that I should do like this:
while (!key[KEY_ESC]) { while (speed > 0) { walk_u = true; walk_d = true; walk_r = true; walk_l = true;
And then the rest of the loop?
You have to use the result of box_check to set the variables that allow your character to walk in a certain direction :
| 1 | int collision_state = 0; |
| 2 | |
| 3 | while (!key[KEY_ESC]) |
| 4 | { |
| 5 | while (speed > 0) |
| 6 | { |
| 7 | walk_u = true; |
| 8 | walk_d = true; |
| 9 | walk_r = true; |
| 10 | walk_l = true; |
| 11 | |
| 12 | collision_state = box_check(character , tree); |
| 13 | |
| 14 | switch (collision_state) { |
| 15 | case collision_none : break; |
| 16 | case collision_left : walk_l = false;break; |
| 17 | case collision_right : walk_r = false;break; |
| 18 | case collision_top : walk_u = false;break; |
| 19 | case collision_bottom : walk_d = false; |
| 20 | default : break; |
| 21 | } |
| 22 | |
| 23 | // Now you can decide whether to let the player walk in a certain direction or not |
| 24 | |
| 25 | // rest of code... |
| 26 | } |
| 27 | } |
Like I said though , this method will let your character overlap other objects by one pixel because it checks whether the character is currently overlapping another object , not whether it would after it moved one in that direction.
Wow, Thanks man!
This code looks really good! I'll try it later, need to go to school now
EDITED: Oh, It didn't work
I used your code and the character couldn't go through the tree but not around it either
I don't understand what's wrong. But thanks anyway!
Warning: this is a very long post.
The box_check function isn't set up right.
int box_check(object &obj1, object &obj2) { if (obj1.bottom == obj2.top) { return collision_bottom; } if (obj1.top == obj2.bottom) { return collision_top; } if (obj1.right == obj2.left) { return collision_right; } if (obj1.left == obj2.right) { return collision_left; } else collision_none; }
The last line should return collision_none, otherwise it won't tell you there wasn't a collision. Also, in the if statements it checks only for the x or y position. This will cause problems. For example:

See how object1.right equals object2.left, setting off the collision check, but the object is above the other. I have fixed the function and changed the way objects are handled so that it is easier to use. I will explain them below.
The new object structure
struct object { int x; int y; int w; int h; BITMAP *image; };
This allows you to easily move and setup the object. This combined with the new collision function make it so you can do this to set them up and move them.
The new collision detection function
| 1 | int box_check(object &obj1, object &obj2,int & ov) |
| 2 | { |
| 3 | if (obj1.y+obj1.h >= obj2.y && obj1.y <= obj2.y+obj2.h && |
| 4 | obj1.x+obj1.w >= obj2.x && obj1.x <= obj2.x+obj2.w) |
| 5 | { |
| 6 | int side = collision_bottom; |
| 7 | int overlap = abs((obj1.y+obj1.h) - obj2.y); |
| 8 | if(abs(obj1.y - (obj2.y+obj2.h)) < overlap) |
| 9 | { |
| 10 | overlap = abs(obj1.y - (obj2.y+obj2.h)); |
| 11 | side = collision_top; |
| 12 | } |
| 13 | if(abs((obj1.x+obj1.w) - obj2.x) < overlap) |
| 14 | { |
| 15 | overlap = abs((obj1.x+obj1.w) - obj2.x); |
| 16 | side = collision_right; |
| 17 | } |
| 18 | if(abs(obj1.x - (obj2.x+obj2.w)) < overlap) |
| 19 | { |
| 20 | overlap = abs(obj1.x - (obj2.x+obj2.w)); |
| 21 | side = collision_left; |
| 22 | } |
| 23 | ov = overlap; |
| 24 | return side; |
| 25 | } |
| 26 | else return collision_none; |
| 27 | } |
This may seem complicated at first, but it is actually pretty simple. First is:
if(obj1.y+obj1.h >= obj2.y && obj1.y <= obj2.y+obj2.h && obj1.x+obj1.w >= obj2.x && obj1.x <= obj2.x+obj2.w)
This checks if there was a collision and works even if the object is not exactly on the edge of the other. It is basically
if(obj1.bottom >= obj2.top && obj1.top <= obj2.bottom && obj1.rgiht >= obj2.left && obj1.left <= obj2.right)
Here is a picture explaining it more.

Next is these lines:
int side = collision_bottom; int overlap = abs((obj1.y+obj1.h) - obj2.y);
The side is the side of collision which is returned, just like in the other function. Overlap is how far one shape is inside the other and should be used to move the shape out. Finally these lines:
This check the next side. If the overlap is less than that is the side closest to the edge and is where it should be removed from. This is continued for all the sides. Then it just sets the overlap variable and returns the side of collision.
Example:
int overlap; collision_state = box_check(character , tree,overlap); switch (collision_state) { case collision_none : overlap = 0; break; case collision_left : character.x += overlap;walk_l = false;break; case collision_right : character.x -= overlap;walk_r = false;break; case collision_top : character.y += overlap;walk_u = false;break; case collision_bottom : character.y -= overlap;walk_d = false; default : break; }
With this you can move the objects larger amounts and it will still collide correctly.
Conclusion
I have attached the revised code for your project. Hopefully this helps you with your problem, sorry that it was so long.:-/ If you have any problems or questions just post again. Happy coding!;D
(bump)
Oh yeah!! I't working!
Thanks man!
I tried to add objects and it worked. Thanks so much! Now I can start working on my game again.
Thanks again!