|
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. 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. Please help me. |
Neil Roy
Member #2,229
April 2002
|
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. 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. 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
Member #16,794
January 2018
|
@Neil Roy Although, the problem has been solved before. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
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"} 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}
Edit This might be nice to try for collision resolution My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Neil Roy
Member #2,229
April 2002
|
Very nice example Edgar! Simple and efficient. --- |
Edgar Reynaldo
Major Reynaldo
May 2007
|
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. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
keprast
Member #16,794
January 2018
|
I think you have a good way of doing it.(*゚∀゚*) 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. It has hundreds of lines. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
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}
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
keprast
Member #16,794
January 2018
|
I think my answer is necessary. And, you know, I'm a learner.I need to accumulate experience. And, believe me, the code is in most cases only the midpoint distance measurement. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
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. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|