How to make a collision box at 360 degrees
keprast

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.

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?

Neil Roy

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.

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

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

@Neil Roy

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

Edgar Reynaldo

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)

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

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}

This might be nice to try for collision resolution

Neil Roy

Very nice example Edgar! Simple and efficient.

Edgar Reynaldo

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

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

Write this：

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

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.

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

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