Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » How to make a collision box at 360 degrees

This thread is locked; no one can reply to it. rss feed Print
How to make a collision box at 360 degrees
keprast
Member #16,794
January 2018

Hello, nice to meet you, no matter who you are.:D

I tried to make a 360 degree collision box.
But it's not good.
It has a strange range of judgment.

#SelectExpand
1 bool ppp = false; 2 3 if (box1_x >= box2_x) { 4 px = box1_x - box2_x; 5 } 6 else 7 { 8 px = box2_x - box1_x; 9 } 10 11 if (box1_y >= box2_y) { 12 py = box1_y - box2_y; 13 } 14 else 15 { 16 py = box2_y - box1_y; 17 } 18 19 pz0 = px*px + py*py; 20 pz1 = box1_h*box1_h + box1_w*box1_w; 21 //std::cout << px; 22 23 pz0 = sqrt(pz0); 24 pz1 = sqrt(pz1); 25 //std::cout << pz0 << std::endl; 26 27 if (pz0 <= box1_w || pz0 <= box1_h || pz0 <= box2_w || pz0 <= box2_h|| pz0 <= pz1) { 28 /*collision*/ 29 ppp = true; 30 } 31 else 32 { 33 /*no collision*/ 34 ppp = false; 35 } 36 37 if (ppp) { 38 x -= Vx; 39 y -= Vy;//Incomplete content 40 41 }

As you can see, I use the vector distance of two coordinates.And these heights and widths.
--------------------------------------------------
I have two questions:
Except for //Incomplete content.Is it right to do this?
If it is wrong, where is it?

Please help me.

NiteHackr
Member #2,229
April 2002
avatar

This is a simple collision detection function I came up with. Rather than checking if two objects overlap, it tests if they do not. This goes against what we would normally do, but it is faster. It checks if the left edge of one box (it's minimum X co-ordinate) is greater than the right edge of another (it's maximum X co-ordinate), than the two cannot be colliding and returns false right away. It does the same for the vertical Y co-ordinates, if the top of one box (minimum Y co-ordinate) is greater than the bottom of another box (maximum Y co-ordinate) than it is impossible for the two to be colliding.

If either of those two tests are true, you can return immediately from this function with a false, or no collision which makes it much faster as most of the time, your objects will not be colliding and you don't want your program hanging around in a function for more time than it needs to.

If BOTH of those tests fail, than you absolutely have a collision and can return true, or process it even further to figure out where they are colliding if needed.

In this example code, I send it the information from a C++ Pong game I made, with the position of the ball and the paddle.

This is of course, simple bounding box collision.

#SelectExpand
1int collision(Ball &ball, Paddle &paddle) 2{ 3 int left1, left2, over_left; 4 int right1, right2, over_right; 5 int top1, top2, over_top; 6 int bottom1, bottom2, over_bottom; 7 int over_width, over_height; 8 int cx, cy; 9 int pixel1, pixel2; 10 11 left1 = (int)ball.get_x(); // get ball's left edge 12 left2 = paddle.get_x(); // get paddle's left edge 13 right1 = (int)ball.get_x() + ball.get_width(); // get ball's right edge 14 right2 = paddle.get_x() + paddle.get_width(); // get paddle's right edge 15 top1 = (int)ball.get_y(); // get ball's top edge 16 top2 = paddle.get_y(); // get paddle's top edge 17 bottom1 = (int)ball.get_y() + ball.get_height(); // get ball's bottom edge 18 bottom2 = paddle.get_y() + paddle.get_height(); // get paddle's bottom edge 19 20 21 // Test if the bounding boxes overlap. 22 // We can safely return false on any of these tests = fast and efficient 23 if(bottom1 < top2) return 0; 24 if(top1 > bottom2) return 0; 25 if(right1 < left2) return 0; 26 if(left1 > right2) return 0; 27 28 29 // Where on the paddle did the ball hit? 30 // This is for a pong game, so I return 1, 2, or 3 to indicate where the ball hit 31 // This could be easily improved with a little trigonometry 32 if(top1 < top2) return 1; // ball hit near top of paddle 33 if(bottom1 > bottom2) return 2; // ball hit near bottom of paddle 34 35 return 3; // ball hit centre area of paddle 36}

For circular collision, this is code I use in my Deluxe Pacman 2 game (link below). Ignore the hack detection code, I put that in there so that if someone hacked my game to cheat (and someone did), than my game would alter itself and make it more difficult to play without making it immediately apparent that it detected the hack. 8-) This is originally intended as pure C code, not C++. Not much of a difference, but just so you understand why I use pointers * in this and references & in the bounding box above. You can't use references like the above in C functions... (just to be clear)...

#SelectExpand
1// Circular collision detection 2bool dp2_collision(PACMAN *p, GHOST *g, bool h) 3{ 4 // If the ghost is already dead, there is no collision 5 if(g->dead) return false; 6 7 double gx = (double)g->x + 16.0; // ghost.x is based on tile size (32), so half that is 16. 8 double gy = (double)g->y + 16.0; // ghost.y is based on tile size (32), so half that is 16. 9 double px = (double)p->x; 10 double py = (double)p->y; 11 double dist_x = px - gx; 12 double dist_y = py - gy; 13 double gr = g->r; 14 15 // Hack detection, increase collision radius if a hack has been detected :) 16 if(h) { 17 gr += 5.0; 18#ifdef DEBUG 19 printf("*** Hack Detected: %d ***\n", __LINE__); 20#endif // DEBUG 21 } 22 23 double rt = abs(p->r + gr); 24 25 if(abs(dist_x) > rt) return false; 26 else if(abs(dist_y) > rt) return false; 27 28 double dist = sqrt((dist_x * dist_x) + (dist_y * dist_y)); // The distance of the vector between the two 29 30 // is the distance less than or equal to the absolute sum of the two radiuses? 31 return dist <= rt; 32}

keprast
Member #16,794
January 2018

@Neil Roy
Thanks for your help.:)

Although, the problem has been solved before.
But your plan is a feature.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Here's a little demo of collision between two bouncers. The circle lights up when they are in circle collision, and the rectangles light up when they are in rectangle collision.

Bounce.zip (src + static win32 binary)

{"name":"611210","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/0\/406980faaea33a30144813ad19902e66.png","w":802,"h":633,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/0\/406980faaea33a30144813ad19902e66"}611210

Collision between two AABB's or two circles is easy.

#SelectExpand
1int SquareCollide(BOUNCER* b1 , BOUNCER* b2) { 2 double lx1 = b1->cx - b1->rw/2.0; 3 double rx1 = b1->cx + b1->rw/2.0; 4 double ty1 = b1->cy - b1->rh/2.0; 5 double by1 = b1->cy + b1->rh/2.0; 6 double lx2 = b2->cx - b2->rw/2.0; 7 double rx2 = b2->cx + b2->rw/2.0; 8 double ty2 = b2->cy - b2->rh/2.0; 9 double by2 = b2->cy + b2->rh/2.0; 10 11 if ((rx1 < lx2) || (lx1 > rx2) || (ty1 > by2) || (by1 < ty2)) {return 0;} 12 13 return 1; 14} 15 16 17 18int CircleCollide(BOUNCER* c1 , BOUNCER* c2) { 19 double dx = c2->cx - c1->cx; 20 double dy = c2->cy - c1->cy; 21 double dr = c1->rad + c2->rad; 22 return ((dx*dx + dy*dy) <= (dr*dr)); 23}

Edit
https://www.allegro.cc/forums/thread/596331/747956#target

This might be nice to try for collision resolution

NiteHackr
Member #2,229
April 2002
avatar

Very nice example Edgar! Simple and efficient.

Edgar Reynaldo
Member #8,592
May 2007
avatar

I've got working circle based intercept collision. In the past, I had intercept collision code for rectangles too. That must be around here somewhere.

I just can't quite get my collision response correct, which is what I'm working on atm.

keprast
Member #16,794
January 2018

I think you have a good way of doing it.(*゚∀゚*)
Although I'm more pragmatic.

Write this:

#SelectExpand
1 barc1_1_x = boxA_1 + (boxR_1*cos(barc1_1)); 2 barc1_1_y = boxB_1 + (boxR_1*sin(barc1_1)); 3 barc1_2_x = boxA_1 + (boxR_1*cos(barc1_2)); 4 barc1_2_y = boxB_1 + (boxR_1*sin(barc1_2)); 5 barc1_3_x = boxA_1 + (boxR_1*cos(barc1_3)); 6 barc1_3_y = boxB_1 + (boxR_1*sin(barc1_3)); 7 barc1_4_x = boxA_1 + (boxR_1*cos(barc1_4)); 8 barc1_4_y = boxB_1 + (boxR_1*sin(barc1_4)); 9 10 barc2_1_x = boxA_2 + (boxR_2*cos(barc2_1)); 11 barc2_1_y = boxB_2 + (boxR_2*sin(barc2_1)); 12 barc2_2_x = boxA_2 + (boxR_2*cos(barc2_2)); 13 barc2_2_y = boxB_2 + (boxR_2*sin(barc2_2)); 14 barc2_3_x = boxA_2 + (boxR_2*cos(barc2_3)); 15 barc2_3_y = boxB_2 + (boxR_2*sin(barc2_3)); 16 barc2_4_x = boxA_2 + (boxR_2*cos(barc2_4)); 17 barc2_4_y = boxB_2 + (boxR_2*sin(barc2_4));

Rotation matrix.
Reliable, but not efficient.

It has hundreds of lines.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Don't create your own rotation matrix unless you have to. It's much simpler to just use allegro's transform api to get your coordinates.

#SelectExpand
1struct VEC2D { 2 float x,y; 3}; 4 5struct RECT { 6 float rw,rh,cx,cy; 7}; 8 9RECT r = { 120.0f , 80.0f , 0.0f , 0.0f }; 10 11VEC2D GetVert(RECT* pr , int vnum , float rot_radians) {/// vnum starts at the upper left and goes clockwise 12 bool left = (vnum/2 == 0); 13 bool down = ((vnum == 1) || (vnum == 2); 14 VEC2D xy = { (left?-pr->rw:pr->rw)/2.0f , (down?-pr->rh:pr->rh)/2.0f }; 15 ALLEGRO_TRANSFORM t; 16 al_identity_transform(&t); 17 al_rotate_transform(&t , rot_radians); 18 al_translate_transform(&t , cx , cy); 19 al_transform_coordinates(&t , &xy.x , &xy.y); 20 return xy; 21}

keprast
Member #16,794
January 2018

I think my answer is necessary.
Sorry, because Allegro's manual is not detailed.I can't understand something.

And, you know, I'm a learner.I need to accumulate experience.
And, my game will be very complicated.
The implicit operation of the Allegro.It's not good for me to think.

And, believe me, the code is in most cases only the midpoint distance measurement.

Edgar Reynaldo
Member #8,592
May 2007
avatar

keprast said:

Sorry, because Allegro's manual is not detailed.I can't understand something.

Allegro's manual is actually pretty good. If you have specific questions about it, ask away.

Go to: