Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allegro collision help!

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Allegro collision help!
Edgar Reynaldo
Major Reynaldo
May 2007
avatar

mrukki
Member #9,433
January 2008

Yeah, but just after those lines I have:

if (key[KEY_RIGHT] && walk_r == true)
charx ++;

if (key[KEY_DOWN] && walk_d == true)
chary ++;

:)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

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.

mrukki
Member #9,433
January 2008

Code!
There's the code! :) I hope you or someone else find the error(s) ;)
Thanks!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

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 
3volatile long speed = 0;
4 
5void increment()
6{
7speed ++;
8}END_OF_FUNCTION(increment);
9 
10struct object
11{
12int left;
13int right;
14int top;
15int bottom;
16BITMAP *image;
17};
18 
19 
20enum
21{
22collision_left,
23collision_top,
24collision_right,
25collision_bottom,
26collision_none
27};
28 
29int box_check(object &obj1, object &obj2)
30{
31if (obj1.bottom == obj2.top) { return collision_bottom; }
32if (obj1.top == obj2.bottom) { return collision_top; }
33if (obj1.right == obj2.left) { return collision_right; }
34if (obj1.left == obj2.right) { return collision_left; }
35else collision_none;
36}
37 
38int main(int argc, char *argv[])
39{
40allegro_init();
41install_keyboard();
42install_timer();
43 
44LOCK_VARIABLE(speed);
45LOCK_FUNCTION(increment);
46install_int_ex(increment, BPS_TO_TIMER(60));
47 
48set_color_depth(24);
49set_gfx_mode(GFX_AUTODETECT, 400,400,0,0);
50 
51 
52BITMAP *image1 = load_bitmap("character.bmp", NULL);
53BITMAP *image2 = load_bitmap("tree.bmp", NULL);
54BITMAP *water = load_bitmap("water.bmp", NULL);
55BITMAP *buffer = create_bitmap(400, 400);
56 
57if (image1 == NULL || image2 == NULL || water == NULL || buffer == NULL)
58{
59set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
60allegro_message("Could not load bitmap!");
61exit(EXIT_FAILURE);
62}
63 
64int charx = 0;
65int chary = 0;
66 
67int l1 = charx;
68int t1 = chary;
69 
70int r1 = (l1 + image1->w);
71int b1 = (t1 + image1->h);
72 
73int l2 = 100;
74int t2 = 100;
75 
76int r2 = (l2 + image2->w);
77int b2 = (t2 + image2->h);
78 
79int l3 = 200;
80int t3 = 0;
81 
82int r3 = (l3 + water->w);
83int b3 = (t3 + water->h);
84 
85bool walk_d = true;
86bool walk_u = true;
87bool walk_r = true;
88bool walk_l = true;
89 
90object character,tree;
91//set up object1
92character.left = l1;
93character.right = r1;
94character.top = t1;
95character.bottom = b1;
96character.image = image1; //assuming that image1 is the bitmap you loaded
97 
98//set up object2
99tree.left = l2;
100tree.right = r2;
101tree.top = t2;
102tree.bottom = b2;
103tree.image = image2;
104 
105while (!key[KEY_ESC])
106{
107while (speed > 0)
108{
109l1 = charx;
110t1 = chary;
111 
112r1 = (l1 + image1->w);
113b1 = (t1 + image1->h);
114 
115character.left = l1;
116character.right = r1;
117character.top = t1;
118character.bottom = b1;
119//--------------------------------
120if (box_check(character, tree) == collision_none)
121{
122return 1;
123}
124//---------------------------------------------
125if (key[KEY_RIGHT] && walk_r == true)
126charx ++;
127 
128if (key[KEY_LEFT] && walk_l == true)
129charx --;
130 
131if (key[KEY_DOWN] && walk_d == true)
132chary ++;
133 
134if (key[KEY_UP] && walk_u == true)
135chary --;
136 
137speed --;
138}
139draw_sprite(buffer, image1, charx, chary);
140draw_sprite(buffer, image2, 100, 100);
141draw_sprite(buffer, water, 200, 0);
142textprintf_ex(buffer, font, 0,0, makecol(255,0,255), -1, "Collision test");
143 
144blit(buffer, screen, 0, 0, 0, 0, 400, 400);
145clear_bitmap(buffer);
146}
147 
148destroy_bitmap(buffer);
149destroy_bitmap(image1);
150destroy_bitmap(image2);
151 
152return 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.

mrukki
Member #9,433
January 2008

Oh, I just used that just to test :P 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? :)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You have to use the result of box_check to set the variables that allow your character to walk in a certain direction :

1int collision_state = 0;
2 
3while (!key[KEY_ESC])
4{
5while (speed > 0)
6{
7walk_u = true;
8walk_d = true;
9walk_r = true;
10walk_l = true;
11 
12collision_state = box_check(character , tree);
13 
14switch (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.

mrukki
Member #9,433
January 2008

Wow, Thanks man! ;D 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!

someone972
Member #7,719
August 2006
avatar

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:

594342
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.

object player;
player.x = 20;
player.y = 20;
player.w = image1->w;
player.h = image1->h;
player.image = image1;

while(!key[KEY_ESC]) {
//...
if(key[KEY_RIGHT])
player.x++;
//etc.
}

The new collision detection function

1int box_check(object &obj1, object &obj2,int & ov)
2{
3if (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 }
26else 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.

594343
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:

if(abs(obj1.y - (obj2.y+obj2.h)) < overlap)
{
  overlap = abs(obj1.y - (obj2.y+obj2.h));
  side = collision_top;
}

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

______________________________________
As long as it remains classified how long it took me to make I'll be deemed a computer game genius. - William Labbett
Theory is when you know something, but it doesn't work. Practice is when something works, but you don't know why. Programmers combine theory and practice: Nothing works and they don't know why. -Unknown
I have recklessly set in motion a chain of events with the potential to so-drastically change the path of my life that I can only find it to be beautifully frightening.

Audric
Member #907
January 2001

(bump)

mrukki
Member #9,433
January 2008

Oh yeah!! I't working! ;D Thanks man! ;) I tried to add objects and it worked. Thanks so much! Now I can start working on my game again. ;D Thanks again!

 1   2 


Go to: