Collideables

There are many times that we may want to check and see whether objects in the game have collided with each other. We may want to see whether the player has struck an obstacle or an enemy. We may have objects that the player can pick up, often called pickups or powerups.

Collectively, objects in the game that can collide with other objects are known as collideables. When we created our Sprite class, we actually it designed for this. Looking at the class constructor, you will notice that member variable m_isCollideable is set to false. When we write our collision detection code, we will ignore objects that have m_isCollideable set to false. If we want to allow an object to collide with other objects, we have to make sure to set m_collideable to true.

Ready to score

To keep our design simple, we are going to create one enemy and one pickup. Running into an enemy will subtract points from the player's score, while running into the pickup will increase the player's score. We will add some additional code to the sprite class to support this feature.

First, let's add some new member variables. Declare a new variable in Sprite.h:

int m_value;

Then add the following methods:

void SetValue(const int p_value) { m_value = p_value; }
const int GetValue() const { return m_value; }

With these changes, every sprite will have an intrinsic value. If the value is positive, then it is a reward. If the value is negative, then it is a penalty.

Don't forget to initialize m_value to zero in the Sprite class constructor!

A friend indeed

Let's add the sprite for our pickup. In this case, the pickup is a can of oil to keep Robo's joints working smoothly.

Add the following sprite definitions to RoboRacer2D:

Sprite* pickup;

Now, we will set up the sprite. Add the following code to LoadTextures:

pickup = new Sprite(1);
pickup->SetFrameSize(26.0f, 50.0f);
pickup->SetNumberOfFrames(1);
pickup->AddTexture("resources/oil.png");
pickup->IsVisible(false);
pickup->IsActive(false);
pickup->SetValue(50);

This code is essentially the same code that we used to create all of our sprites. One notable difference is that we use the new SetValue method to add a value to the sprite. This represents how many points the player will earn for the collection of this pickup.

Time to spawn

Note that we have set the sprite as inactive and invisible. Now, we will write a function to randomly spawn the pickup. First, we need to add two more C++ headers. In RoboRacer2D.cpp add the following headers:

#include <stdlib.h>
#include <time.h>

We need stdlib for the rand function and time to give us a value to seed the random generator.

Tip

Random numbers are generated from internal tables. In order to guarantee that a different random number is chosen each time the program is started, you first seed the random number generator with a value that is guaranteed to be different each time you start the program. As the time that the program is started will always be different, we often use time as the seed.

Next, we need a timer. Declare the following variables in RoboRacer2D.cpp:

float pickupSpawnThreshold;
float pickupSpawnTimer;

The threshold will be the number of seconds that we want to pass before a pickup is spawned. The timer will start and zero and count up to that number of seconds.

Let's initialize these values in the StartGame function. The StartGame function is also a great place to seed our random number generator. Add the following three lines of code to the end of StartGame:

srand(time(NULL));
pickupSpawnThreshold = 15.0f;
pickupSpawnTimer = 0.0f;

The first line seeds the random number generator by passing in an integer representing the current time. The next line sets a spawn threshold of 15 seconds. The third line sets the spawn timer to 0.

Now, let's create a function to spawn our pickups. Add the following code to RoboRacer2D.cpp:

void SpawnPickup(float p_DeltaTime)
{
  if (pickup->IsVisible() == false)
  {
    pickupSpawnTimer += p_DeltaTime;
    if (pickupSpawnTimer > pickupSpawnThreshold)
    {
      float marginX = pickup->GetSize().width;
      float marginY = pickup->GetSize().height;
      float spawnX = (rand() % (int)(screen_width - (marginX * 2))) + marginX;
      float spawnY = screen_height - ((rand() % (int)(player->GetSize().height - (marginY * 1.5))) + marginY);
      pickup->SetPosition(spawnX, spawnY);
      pickup->IsVisible(true);
      pickup->IsActive(true);
      pickupSpawnTimer = 0.0f;
    }
  }
}

This code does the following:

  • It checks to make sure that the pickup is not already on the screen
  • If there is no pickup, then the spawn timer is incremented
  • If the spawn timer exceeds the spawn threshold, the pickup is spawned at a random position somewhere within the width of the screen and within the vertical reach of Robo

Don't get too worried about the particular math being used. Your algorithm to position the pickup could be completely different. The key here is that a single pickup will be generated within Robo's reach.

Make sure to add a call to SpawnPickup in the Update function as well as a line to update the pickup:

if (m_gameState == GS_Running)
{
  background->Update(p_deltaTime);
  robot_left->Update(p_deltaTime);
  robot_right->Update(p_deltaTime);
  robot_left_strip->Update(p_deltaTime);
  robot_right_strip->Update(p_deltaTime);
  
  pause->Update(p_deltaTime);
  resume->Update(p_deltaTime);
  
  pickup->Update(p_deltaTime);
  SpawnPickup(p_deltaTime);
}

We also need to add a line to Render to render the pickup:

void Render()
{
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  
  background->Render();
  robot_left->Render();
  robot_right->Render();
  robot_left_strip->Render();
  robot_right_strip->Render();
  
  pause->Render();
  resume->Render();
  
  pickup->Render();
  SwapBuffers(hDC);
}

If you run the game right now, then an oil can should be spawned about five seconds after the game starts.

Tip

The current code has one flaw. It could potentially spawn the pickup right on top of Robo. Once we implement collision detection, the result will be that Robo immediately picks up the oil can. This will happen so quickly that you won't even see it happen. In the name of keeping it simple, we will live with this particular flaw.

..................Content has been hidden....................

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