2D collision: AARRRGHHH

For the last two days I've been trying to get a (seemingly) simple algo working:
A detection system for my own Breakout clone. I use y = ax+b as function for to calc the trajectory of the ball. But there's something tricky about the grid because of the way openGL laid it out, it goes like this:

1
2
3
4
5
6
7
8
    1    2    3   4
1

2

3

4



this is what I have up until now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool Brick::collision(float &x, float &y, float &vx, float &vy, class Ball &ball)
{
    // with vy and vx being the amount of pixels to move per update (negative vy means going upwards!
   // x and y are the current position of the ball
    float a = vy/vx; // calculate equation
    float b = y-(a*x); //offset
    //equation is now: y = ax + b

    float right = row * WIDTH + WIDTH;
    float left = row * WIDTH;
    float top = col * HEIGHT;
    float bottom = col * HEIGHT + HEIGHT;
    //capture specifics of the brick, taking the special layout into account

    float x_ = -(bottom-b)/a; // what's X if y = bottom?


    if(y > bottom) // if it's already above the brick no collision
        return false;


    if(vy < 0) //for now, only test going upwards
    {

        if( x_ > left  && x_ < right && bottom < y)
        {
            vy = -vy;
            return true;
        }
     }




    return false;
}


The thing is, it NEVER detects anything, it just goes through everything!


Many thanks in advance :)
Last edited on
Hello,

I am much n00ber than you.

in line 25 try having x_ > left and x_<= right or vice versa
and lines 18, 25: y_ >bottom and y_<=bottom or vice versa
so you'll have all cases covered.

Just my shot in the dark.
Thanks for spotting that little bug nand, but it didn't fix the problem so I'm still looking for answers :D
bump...
re-explain your primary goal because I'm wondering what exactly it is. You may end up getting better solutions than the ones you have created (I know from personal experience).

Anyway from the look of your collision detection system, I don't think its a proven one because I find it strange, bear in mind there isn't the perfect collision detection system since its all based on purpose. But instead try the bounding boxes AABB collision detection system.

My code from my Open GL system

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 bool Test_Collision(GLfloat AA_Vector_X0, GLfloat AA_Vector_X1, //Box 1, min & max X_length
	                     GLfloat AA_Vector_Y0,GLfloat AA_Vector_Y1, //Box 1, min & max Y_length
	                          GLfloat BB_Vector_X0,  GLfloat BB_Vector_X1, //Box 2, min & max X_length
	                                GLfloat BB_Vector_Y0,GLfloat BB_Vector_Y1)//Box 2, min & max Y_length
{  //Test for collision
	//min1 < max2 && min2 < max1

	   //Test Vector X axis                                                                    
	if((AA_Vector_X0 < BB_Vector_X1) && (BB_Vector_X0 < AA_Vector_X1)
	   //Test Vector Y axis
	 && (AA_Vector_Y0 < BB_Vector_Y1) && (BB_Vector_Y0 < AA_Vector_Y1))		
	return true;  //collision true
	else
	return false;  //collision false
}


CHECK THIS SITE TOO: http://www.flipcode.com/archives/Theory_Practice-Issue_01_Collision_Detection.shtml
@ OP: Why are you passing in so many variables? The coordinates of your object should be members and therefore accessable from within the same scope; translation: you should not need to pass them into this function.

Stop naming your variables like this is your first program. I really wish tutorials would stop teaching like this as it's a hard habbit to break. But your code will become much easier to read once you can look at a variable and know already what it is.

Also, class Ball &ball? Is this a template? Did you define this object in this scope yet?

Lines 9 - 12 should already be avalible as data members of the object. This is simply so that you don't have to keep re-writing this everytime you need those variables.
The class Ball &ball is a variable i forgot to delete. for some reason it wouldn't work that way, because of dependencies etc.
@Blessman11: At first I used a system where it would simply check everytime it moved. But since I was moving 4 pixels a time, it could sometimes cut off a corner, you see?
By using an equation and testing it that way I try to avoid it...
closed account (D80DSL3A)
Where does the variable y_ (on line 18) come from?
ohh oops I forgot...I declared wait i'll edit my post!
closed account (D80DSL3A)
In that case, I think I see why the function always returns false.
Lines 18, 19:
1
2
if(y > bottom) // if it's already above the brick no collision
        return false;

Since y increases downward, y > bottom is below the brick, not above it.
If the test on line 18 is failed (ie y <= bottom ) then execution may get to line 25, where the same test is repeated if( x_ > left && x_ < right && bottom < y)
Note: bottom < y is the same condition as y > bottom. Line 28 can never be reached.

I haven't tested your code but I think the concept won't work well. Your equation of a line produces the path which the ball will follow. The variable x_ is where the ball would be if its y position was at the bottom of the brick, so the test will return true even if the ball is currently well below the brick. A collision is detected if the ball will ever strike the brick.

EDIT: I have my own ball and brick classes written for a blockout type game. It works well and even handles corner strikes (ball striking a brick corner) in addition to face strikes. I let the ball do the collision testing. I'd be happy to share it with you if you like. Unfortunately, it's dependent on other classes written to support it (2d vector and 2d matrix for working with coordinate transformations).
I've noted though that most people don't want to see other peoples code, they want to figure it out themselves. I totally understand that - I operate that way myself.
Last edited on
Well, fun2code, I think that could be very helpful, just to see how you went about the problem. I won't copy your code, because I wouldn't learn anything that way. Could you maybe send me it over PM?
And I do know that it *should* always return true if it ever passes a block in its path, it was just a test :p
Thanks!
If your testing circles for collisions, why use the bounding box method? Why not just test circular areas using a 2d version of bounding spheres? Just calculate the distance between two objects, then subtract that distance by both objects "radius". If the remainder is <=0, you have a collision.

Like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//need to include cmath

class ball {
    public:
        int x, y, rad; //x/y and radius
    };

int sqrd(int num){
    return num*num;}

bool check_col(ball* b1, ball* b2){
    int dis; //distance

    dist = sqrt( sqrd(b1->x - b2->x) + sqrd(b1->y - b2->y)); //calculates distance (straight line)
    dis -= b1->rad; //subtract radiuses
    dis -= b2->rad;

    if (dis<=0) //collision
    return true;

    //no collision
    return false;}


This method will be more accurate for circular objects than bounding box, but is less accurate for rectangular objects.
sqrt? in my collision detection code?

blech!

Better:

1
2
3
4
5
6
7
bool check_col(ball* b1, ball* b2)
{
  int distsq = sqrd( b1->x - b2->x ) + sqrd( b1->y - b2->y );
  int gap = sqrd( b1->rad + b2->rad );

  return distsq <= gap;
}
Last edited on
Well, that'd be a great way to test for collisions with circles, but in my game I need to test rectangles...
1
2
3
4
5
6
7
8
9
10
11
12
// assuming rects have l, r, t, b (left right, top, bottom) members
// assuming y grows downward (b > t)

bool check_col(const rect& a, const rect& b)
{
  if(a.l > b.r)  return false;
  if(a.r < b.l)  return false;
  if(a.t > b.b)  return false;
  if(a.b < b.t)  return false;

  return true;
}
Wouldn't that cause corner-cutting?
if objects are moving fast enough, yes. If you want to avoid that kind of situation your physics and movement will need to get a lot more complicated.

I have a vector-based collision detection system in my game that addresses those issues, but the code of it is quite large. There are also premade libs that handle it for you if you don't want to write one yourself (box2d is popular).

But if you just want something simple that works well enough, you can use the above.
Well I guess I'll use that for now. I'll look into Box2D later though!
Thanks all!
Topic archived. No new replies allowed.