Collision Detection problem!!!

Started by
7 comments, last by tom76 22 years, 5 months ago
I''m working on a variation of Donuts 3D, my terrain for example has several blocks, which the player bounces off of. The problem is that I''m using the D3DXVec3Normalize function, and this makes the player bounce off in the same direction no matter what side of the block he/she touches (going through the block in some cases).
  
        // top block

	if( (g_pShip->vPos.x < +1.7f && g_pShip->vPos.x > -0.2f &&  // block at top  

       g_pShip->vPos.y < -2.7f && g_pShip->vPos.y > -3.8f ) )   
    {
         D3DXVec3Normalize( &g_pShip->vVel, &g_pShip->vPos );
         g_pShip->vVel.x *= -1.0f;                      
         g_pShip->vVel.y *= -1.0f;                     
         g_pShip->vVel.z *= -1.0f;
    }
  
I think what I need is to make the player bounce off at the OPPOSITE angle, but how can I do this? "I envy you, who has seen it all" "And I, young sir, envy you, who have yet to see it for the first time..." - Daniel Glenfield 1st October 2001
if (witisism == !witty) return to_hole
Advertisement
Just copying a chunck from the NeHe OpenGL Collision Detection Tutorial (#31) by Dimitrios Christopoulos (christop@fhw.gr), to find the vector you need the ship to bounce back with, do the following:
--------- plane   /|`  / | ` /  |  `/   |   `I   N   R

R= 2*(-I dot N)*N + I

where R is the outbound vector (after the bounce)
I is a unit vector representing the direction the ship was travelling before the bounce
N is a unit vector representing the plane's normal vector

This means that R will be a unit vector and you will need to multiply by the speed the ship was travelling to start with.

Hope this helps

EDIT: credit where credit's due (forgot to mention the person who wrote the tutorial)

EDIT: for some reason the first edit changed my pre, /pre tags into code, /code tags! x3!

Edited by - Enigma on October 29, 2001 8:30:07 AM
I''d love to say that solved all my problems, but I''m having trouble implementing it!!! I tried using D3DXVec3Normalize but I can''t do N = D3DXVec3Normalize because it''s a structure. ARGH!!! Anybody?

"I envy you, who has seen it all"
"And I, young sir, envy you, who have yet to see it for the first time..."
- Daniel Glenfield
1st October 2001
if (witisism == !witty) return to_hole
Can't tell if this will work (I don't really know DirectX), but try:
D3DXVECTOR3 i = &g_ship->vVel / D3DXVEC3Length(g_ship->vVel); 

I don't know how you store your blocks, so I can't say how to get the plane's normal vector.

Edited by - Enigma on October 29, 2001 12:20:42 PM
I''ll give that a try, thanks mate!

"I envy you, who has seen it all"
"And I, young sir, envy you, who have yet to see it for the first time..."
- Daniel Glenfield
1st October 2001
if (witisism == !witty) return to_hole
Couldn'' get it to work, though not through lack of trying!
In fact I deleted the Normalize bit and left myself with
g_pShip->vVel.x *= -1.0f;
g_pShip->vVel.y *= -1.0f;
g_pShip->vVel.z *= -1.0f;

and now the player bounces back along the opposite vector (so you go backwards, the same way you came).

Any mathematical trickery we can do here?

"I envy you, who has seen it all"
"And I, young sir, envy you, who have yet to see it for the first time..."
- Daniel Glenfield
1st October 2001
if (witisism == !witty) return to_hole
Can''t think of any mathematical trickery without knowing the normal vector of the plane. For this you need to know which of the four sides of the block the ship hit.

Assuming that your ship is currently at position (vPos.x, vPos.y) = A and was at position (vPos.x - vVel.x, vPos.y - vVel.y) = B, we need to know where the line AB crosses the block.
So, either vPos.x - p(vVel.x) = x-coord of one side of block, or vPos.y - q(vVel.y) = y-coord of top/bottom of block. This gives four cases:
  // when does the ship hit the left side?double p = -1; // no collisionif (g_pShip->vVel.x != 0) // if there will be a collision   p = (g_pShip->vPos.x - block''s_left_x_coord)/(g_pShip->vVel.x);// when does the ship hit the right side?double q = -1; // no collisionif (g_pShip->vVel.x != 0) // if there will be a collision   q = (g_pShip->vPos.x - block''s_right_x_coord)/(g_pShip->vVel.x);// when does the ship hit the top?double r = -1; // no collisionif (g_pShip->vVel.y != 0) // if there will be a collision   r = (g_pShip->vPos.y - block''s_top_y_coord)/(g_pShip->vVel.y);// when does the ship hit the bottom?double s = -1; // no collisionif (g_pShip->vVel.y != 0) // if there will be a collision   s = (g_pShip->vPos.y - block''s_bottom_y_coord)/(g_pShip->vVel.y);int sideHit = 0; // 1 = left, 2 = right, 3 = top, 4 = bottomdouble timeHit = 1; // we may hit two sides, we need to know which we hit firstD3DXVECTOR3 normal(-1, 0, 0); // assume hit rightif (p >= timeHit && p <= 1){   sideHit = 1;   timeHit = p;}if (q >= timeHit && q <= 1){   sideHit = 2;   timeHit = q;   normal = D3DXVECTOR3(1, 0, 0);}if (r >= timeHit && r <= 1){   sideHit = 3;   timeHit = r;   normal = D3DXVECTOR3(0, 1, 0);}if (s >= timeHit && s <= 1){   sideHit = 4;   timeHit = s;   normal = D3DXVECTOR3(0, -1, 0);}if (sideHit > 0){   // calculate initial speed of ship   float speed = D3DXVec3Length(&(g_pShip->vVel));   // find unit vector in direction g_pShip->vVel   D3DXVECTOR3 initialDirection((g_pShip->vVel.x)/speed, (g_pShip->vVel.y)/speed, 0);   // use R= 2*(-I dot N)*N + I   double minusIDotN = initialDirection.x * normal.x;   minusIDotN += initialDirection.y * normal.y;   minusIDotN = -minusIDotN;   D3DXVECTOR3 minusIDotNTimesN(minusIDotN * normal.x, minusIDotN * normal.y, 0);   D3DXVECTOR3 minusIDotNTimesNPlusI(minusIDotNTimesN.x + initialDirection.x, minusIDotNTimesN.y + initialDirection.y, 0);   D3DXVECTOR3 unitResult(2 * minusIDotNTimesNPlusI.x, 2 * minusIDotNTimesNPlusI.y, 0);   // multiply back up by speed to get final velocity vector   D3DXVECTOR3 vel(speed * unitResult.x, speed * unitResult.y, 0);}// if !(sideHit > 0) then something has gone badly wrongelse   PANIC!; // an error has occured somewhere  


So basically:
1. We find out when we hit each face of the block
2. We find which face we hit first and that face''s normal(latest time < 1 because we are working back from inside the block outwards)
3. We use R= 2*(-I dot N)*N + I to work out the response vector

Note - A, I''ve done all the vector operations myself because I don''t know how D3DXVECTOR3 works.
B, I''ve written this pretty quickly and haven''t tested it - you''ll probably get ''PANIC!'' behaviour for a while until you iron out all the bugs!
Thanks Enigma, I really appreciate all the effort you''ve put into helping me.
Fundamental problem - I''ve not created the object with vectors (it''s a clumsy nasty way of adding a block to the terrain''s X file and then if the player comes near an area of the terrain to bounce back). I realised it after I''d got the bugs weeded out.

Because I''ve got to get this polished up by the end of the week I''ve decided to use a sneaky trick to get round it. These ordinary blocks will become "direction blocks", so if an enemy/player touches them they always go in the direction the arrow points (conveniently in the direction of the normal). My problem was enemies ended up bouncing between two blocks, so I''m working on a randomiser now.

Thanks for all your help, I''ll work on implementing it in my next project. I''ve learnt plenty from this little jaunt though

Many many thanks!

"I envy you, who has seen it all"
"And I, young sir, envy you, who have yet to see it for the first time..."
- Daniel Glenfield
1st October 2001
if (witisism == !witty) return to_hole
Hang about...this code works!!! I don't believe this, it's so simple! (this is for enemies btw, not the ship)

    // Keep object in bounds in X            if( pObject->vPos.x < -3.95f || pObject->vPos.x > +4.05f )            {                if( pObject->vPos.x < -3.95f ) pObject->vPos.x = -3.95f;                if( pObject->vPos.x > +4.05f ) pObject->vPos.x = +4.05f;                pObject->vVel.x = -pObject->vVel.x;            }            // Keep object in bounds in Y            if( pObject->vPos.y < -4.25f || pObject->vPos.y > +4.25f )            {                if( pObject->vPos.y < -4.25f ) pObject->vPos.y = -4.25f;                if( pObject->vPos.y > +4.25f ) pObject->vPos.y = +4.25f;                pObject->vVel.y = -pObject->vVel.y;            }    


"I envy you, who has seen it all"
"And I, young sir, envy you, who have yet to see it for the first time..."
- Daniel Glenfield
1st October 2001

Edited by - tom76 on October 30, 2001 11:21:19 AM
if (witisism == !witty) return to_hole

This topic is closed to new replies.

Advertisement