# Car Collision

Thanks to the preceding code I already knew how to check if the car collides with one of the guard rails. I would just build two collision planes, one for each guard rail, and then I would check if any of the four wheels collide with these collision planes. Because the car is not just a sphere and can’t be handled as easily as the asteroids, all four sides have to be checked, but just checking the four wheel positions (or at least the most outer parts of the car) still allows you to do the basic collision detection (see Figure 13-15).

Figure 13-15

The code for these collision checks can be found in the ApplyGravityAndCheckForCollisions method of the CarPhysics class. The code basically goes through all four car corners and checks if any of them are not between the collision planes (see the two lines on either side of the road in Figure 13-15). The four car corners are defined by calculating the car corners based on actual car length and width values:

`  // Check all 4 corner points of our car. Vector3 carRight = Vector3.Cross(carDir, carUp); Vector3 carLeft = -carRight; // Car dimensions are 2.6m (width) x 5.6m (length) x 1.8m (height) // Note: This could be improved by using more points or using // the actual car geometry. // Note: We ignore the height, this way the collision is simpler. // We then check the height above the road to see if we are flying // above the guard rails out into the landscape. Vector3[] carCorners = new Vector3[] {   // Top left   pos + carDir * 5.6f/2.0f - carRight * 2.6f/2.0f,   // Top right   pos + carDir * 5.6f/2.0f + carRight * 2.6f/2.0f,   // Bottom right   pos - carDir * 5.6f/2.0f + carRight * 2.6f/2.0f,   // Bottom left   pos - carDir * 5.6f/2.0f - carRight * 2.6f/2.0f, }; `

The collision test is now relatively easy thanks to all the helper values that have been calculated before in this method:

`  // Check for each corner if we collide with the guard rail for (int num = 0; num < carCorners.Length; num++) {   // Hit any guardrail?   float leftDist = Vector3Helper.DistanceToLine(     carCorners[num], guardrailLeft, nextGuardrailLeft);   float rightDist = Vector3Helper.DistanceToLine(     carCorners[num], guardrailRight, nextGuardrailRight);   // If we are closer than 0.1f, thats a collision!   if (leftDist < 0.1f ||     // Also include the case where we are farther away from rightDist     // than the road is wide.     rightDist > roadWidth)   {     // Handle collision with left guard rail here   } // if (leftDist < 0.1f)   if (rightDist < 0.1f ||     // Also include the case where we are farther away from leftDist     // than the road is wide.     leftDist > roadWidth)   {     // Handle collision with right guard rail here   } // if (rightDist < 0.1f) } // for (num) `

The final part of the collision handling is now to respond to this collision event. But before you do that you should set some field in your unit test to show you that your collision detection code works. Or just set a breakpoint inside the “if” statement blocks to see if you ever reach the conditions.

Now all you have to do is to play the crash sound and rotate the car around depending on which of the four car corners had the collision. The car will also be slowed down and you let the camera wobble a bit to notify the player that he just crashed. If the collision was straight ahead (0–45 degrees to the wall), you immediately stop the car and play the total crash sound:

`  // Force car back on the road, for that calculate impulse and // collision direction (same stuff as in Rocket Commander). Vector3 collisionDir =   Vector3.Reflect(carDir, guardrailRightNormal); float collisionAngle =   Vector3Helper.GetAngleBetweenVectors(     carLeft, guardrailRightNormal); // Flip at 180 degrees (if driving in wrong direction) if (collisionAngle > MathHelper.Pi / 2)   collisionAngle -= MathHelper.Pi; // Just correct rotation if collison happened at 0-45 degrees (slowly) if (Math.Abs(collisionAngle) < MathHelper.Pi / 4.0f) {   // Play crash sound   Sound.PlayCrashSound(false);   // For front wheels to full collision rotation, for back half!   if (num < 2)   {     rotateCarAfterCollision = +collisionAngle / 1.5f;     speed *= 0.935f;//0.85f;     if (viewDistance > 0.75f)       viewDistance -= 0.1f;//0.15f;   } // if (num)   else   {     rotateCarAfterCollision = +collisionAngle / 2.5f;     //slowdownCarAfterCollision = 0.8f;     speed *= 0.96f;//0.9f;     if (viewDistance > 0.75f)       viewDistance -= 0.05f;//0.1f;   } // else   // Shake camera   ChaseCamera.SetCameraWobbel(0.00075f * speed); } // if (collisionAngle) // If 90-45 degrees (in either direction), make frontal crash // + stop car + wobble camera else if (Math.Abs(collisionAngle) < MathHelper.Pi * 3.0f / 4.0f) {   // Also rotate car if less than 60 degrees   if (Math.Abs(collisionAngle) < MathHelper.Pi / 3.0f)     rotateCarAfterCollision = +collisionAngle / 3.0f;   // Play crash sound   Sound.PlayCrashSound(true);   // Shake camera   ChaseCamera.SetCameraWobbel(0.005f * speed);   // Just stop car!   speed = 0; } // if (collisionAngle) // For all collisions, kill the current car force carForce = Vector3.Zero; // Always make sure we are OUTSIDE of the collision range for // the next frame. But first find out how much we have to move. float speedDistanceToGuardrails =   speed * Math.Abs(Vector3.Dot(carDir, guardrailLeftNormal)); if (rightDist > 0) {   float correctCarPosValue = (rightDist + 0.01f +//0.11f +     0.1f * speedDistanceToGuardrails * moveFactor);   carPos += correctCarPosValue * guardrailRightNormal; } // if (rightDist) `

With this code you are now able to test the TestCarPhysicsOnPlaneWithGuardRails unit test and fine-tune the crashing into the guard rails. The code for the game is a little bit more complex, but the same rules apply and all the collision code and physics calculations are exactly the same as you use for the unit test.

Professional XNA Programming: Building Games for Xbox 360 and Windows with XNA Game Studio 2.0
ISBN: 0470261285
EAN: 2147483647
Year: 2007
Pages: 138

Similar book on Amazon