Collision detection

In the previous part of this chapter, you prepared the ReachPlanet and CrashWithAsteroid methods. However, you cannot detect situations when the rocket reaches the planet or is crashed. In this part, you will implement a mechanism of detecting collisions between the rocket and other objects in the game world.

Concept

There are many approaches for solving the problem of detecting collisions between objects. One of the common approach is based on an idea of bounding sphere (see the following figure). This approach simplifies the process of finding collisions between elements, because each of them is represented as a sphere. Therefore, you can simply compare distance between centers of two spheres and their radiuses. This approach can be very beneficial for detecting collisions between objects similar to spheres. Such a situation occurs in your game, because the planet is simply a sphere and the asteroid is very similar to it.

Concept

The bounding sphere solution can be even further simplified by detecting collisions between a point and a sphere. Such an approach is used in your game to check whether the rocket reaches the planet or hits any asteroid. The sphere is represented by the planet or asteroid and the point is represented by the location of the rocket.

A distance between any two points in three-dimensional space can be calculated with the following formula:

Concept

where A x, A y, A z denote coordinates of the first point (A), and B x, B y, B z are coordinates of the other point (B). The calculated distance is then compared with a radius of the sphere. If it is equal or less, the collision occurs. Otherwise, the point is located outside the sphere.

Implementation

The implementation consists of creating a new class (named CollisionDetector) and making some minor modifications in the GameRenderer class.

CollisionDetector class

The mechanism of collision detection is implemented in the CollisionDetector class. You should not forget to add using directive for DirectX in the header file.

The code of the CollisionDetector class is as follows:

class CollisionDetector
{
public:
  bool static IsHit(XMFLOAT3 point, XMFLOAT3 sphere, float radius);
};

The class contains only one static method (IsHit), which takes three parameters, coordinates of the point, coordinates of a center of the sphere, and the radius of the sphere. The method returns a value indicating whether a collision is detected.

An implementation of the IsHit method is related to the formula presented earlier. Its value is calculated and then compared with the radius. At the end, the result is returned, as shown in the following code:

bool CollisionDetector::IsHit(XMFLOAT3 point, XMFLOAT3 sphere,
  float radius)
{
float distance = sqrt(
  (point.x - sphere.x) * (point.x - sphere.x)
  + (point.y - sphere.y) * (point.y - sphere.y)
  + (point.z - sphere.z) * (point.z - sphere.z));
  return distance <= radius;
}

GameRenderer class

Some changes in the GameRenderer class are also required to detect collisions. At the beginning, you include the CollisionDetector.h file, and then declare three private methods called ReachPlanet, Crash, and DetectCollisions:

void ReachPlanet();
void Crash();
void DetectCollisions();

The first method is called when the rocket reaches the planet. The second is used when the rocket misses the planet or hits any asteroid. The DetectCollisions method is called to check whether any collision between the rocket and either the target planet or asteroids occurs.

The main code related to detecting collisions is placed in the DetectCollisions method, as shown in the following block:

void GameRenderer::DetectCollisions()
{
  bool isPlanetHit = CollisionDetector::IsHit(
    m_rocket.GetLocationSimple(), m_planet.GetLocation(),
    m_planet.GetScale());
  if (isPlanetHit) { ReachPlanet(); }
  bool isAnyAsteroidHit = false;
  for (auto a = m_asteroids.begin(); a != m_asteroids.end(); ++a)
  {
    bool isAsteroidHit = CollisionDetector::IsHit(
      m_rocket.GetLocationSimple(), a->get()->GetLocation(),
      a->get()->GetScale());
    if (isAsteroidHit)
    { 
      isAnyAsteroidHit = true; 
      break; 
    }
  }
  bool missPlanet =
    m_rocket.GetZ() < -m_game.GetDistanceToPlanet() - 5;
  if (isAnyAsteroidHit || missPlanet) { Crash(); }
}

Here, you check whether the rocket reaches the planet. To do it, you can use the CollisionDetector class and pass the location of the rocket, as well as the location and the radius of the planet as parameters of the IsHit method. It is worth mentioning that radius of the planet is equal to its scale, because in your model each vertex coordinate in the planet model takes values in range <-1;1>, thus the radius is equal to 1. If the method returns TRUE, it means that you have reached the planet. Then, you should call the ReachPlanet method.

You also need to ensure that the rocket does not hit any asteroid. It can be achieved by iterating through a collection of asteroid data and calling the IsHit method from the CollisionDetector class. If any asteroid is hit, the value of the isAnyAsteroidHit variable is set to TRUE and you exit the loop. Then, you verify whether the rocket misses the planet. At the end, you check whether the value of the isAnyAsteroidHit or missPlanet variable is equal to TRUE. In such a case, you call the Crash method.

You also need to call the DetectCollisions method inside the Update method, as shown in the following code:

void GameRenderer::Update(float timeTotal, float timeDelta)
{ (...)
  DetectCollisions();
  float distance = m_rocket.Fly(
    timeDelta * 1.5f * m_game.GetSpeedFactor()); (...)
}

The ReachPlanet method is executed when the rocket reaches the planet. It calls the ReachPlanet method (on the Game instance), which increases the number of the current level. Then, it loads the next stage, by calling the LoadLevel method, as shown in the following code:

void GameRenderer::ReachPlanet()
{
  m_game.ReachPlanet();
  LoadLevel();
}

Whenever the user crashes the rocket, the Crash method is executed. Here, the CrashWithAsteroid method (on the Game instance) is called and the same level is restarted, unless the player runs out of rockets, as presented as follows:

void GameRenderer::Crash()
{
  m_game.CrashWithAsteroid();
  if (m_game.GetRocketsNumber() > 0) { LoadLevel(); }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.136.142