Collisions

Well, so far so good. However, we haven't implemented any collision handling. Luckily, LibGDX contains really useful tools to check for collision between the shapes that we are using. This is going to make our lives a lot easier.

The one class we will use is the Intersector class. To find out more, visit http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/math/Intersector.html and take a look at its API, you will see all sorts of useful methods there. However, we are only going to use two of them:

boolean overlaps(Circle c1, Circle c2)
boolean overlaps(Circle c, Rectangle r)

These will return true if the shapes overlap.

So, let's add a method to our Flower class that will take an instance of Flappee in and check the collision areas, as follows:

public boolean isFlappeeColliding(Flappee flappee) {
  Circle flappeeCollisionCircle = flappee.getCollisionCircle();
  return
  Intersector.overlaps(flappeeCollisionCircle, ceilingCollisionCircle) ||
  Intersector.overlaps(flappeeCollisionCircle, floorCollisionCircle) ||
  Intersector.overlaps(flappeeCollisionCircle, ceilingCollisionRectangle) ||
  Intersector.overlaps(flappeeCollisionCircle, floorCollisionRectangle);
}

This should also take place before adding the getter to the Flappee class; otherwise, this code will not compile. All we are doing here. What we are doing here, is checking the different collision areas and returning true if at least one of them overlapped.

Now, let's plug this into the GameScreen class. We can create a method to iterate the obstacles in play and check for collision, as follows:

private boolean checkForCollision() {
  for (Flower flower : flowers) {
    if (flower.isFlappeeColliding(flappee)) {
     return true;
    }
  }
  return false;
}

Then, in our update() method, we can check for the following code snippet:

private void update(float delta) {
  updateFlappee();
  updateFlowers(delta);
  if (checkForCollision()) {
    restart();
  }
}

I snuck a little restart method in there, which is as follows:

private void restart() {
  flappee.setPosition(WORLD_WIDTH / 4, WORLD_HEIGHT / 2);
  flowers.clear();
  score = 0;
}

So now, when Flappee collides with any of the obstacles, the game will—quite crudely, mind you—restart.

Scoring

Finally, to make this more game-like, we will need to add some scoring. The original game gave the player a point every time they cleared an obstacle, so let's do the same.

To do this, we need to consider a few things. First, we will need a way to identify whether the player has cleared an obstacle. Second, we need to ensure that we only reward the player once for each obstacle cleared; finally, how are we going to display the score to the player?

Let's tackle this first issue. We should award a point when the x coordinate of Flappee is greater than the x coordinate of the obstacle; remember, the obstacles move, Flappee does not. This, as it turns out, is quite straightforward; in our GameScreen class, let's add a property to look after the score:

private int score = 0;

Next, let's have a method to update the score, given the parameters we just discussed:

private void updateScore() {
  Flower flower = flowers.first();
  if (flower.getX() < flappee.getX()) {
    score++;
  }
}

Finally, add the following code snippet to our update() method:

private void update(float delta) {
  updateFlappee();
  updateFlowers(delta);
  updateScore();
  if (checkForCollision()) {
    restart();
  }
}

Now, when you play the game, a score will add up. However, it will add up quickly. As the obstacle passes Flappee, the game will still validate the updateScore() as Flappee is passing an obstacle. So the player will get multiple points for clearing the same obstacle! This is something we don't want to do. So, how do we go about solving this problem? One way is to add a flag to the obstacle to say we have claimed the point for it.

In our Flower class, let's add a Boolean flag:

private boolean pointClaimed = false;

Next, let's add some access methods:

public boolean isPointClaimed() {
  return pointClaimed;
}

public void markPointClaimed() {
  pointClaimed = true;
}

Now, let's update our updateScore() method in the GameScreen class:

private void updateScore() {
  Flower flower = flowers.first();
  if (flower.getX() < flappee.getX() && !flower.isPointClaimed()) {
    flower.markPointClaimed();
    score++;
  }
}

Hooray! Now only a single point will be added to the player's score.

Finally, let's have the score shown on the screen. This is going to be fairly similar to what we did with the Snake game.

Let's add BitmapFont to our GameScreen class:

private BitmapFont bitmapFont;
private GlyphLayout glyphLayout;
public void show() {
  /** Code omitted for brevity **/
  bitmapFont = new BitmapFont(); 
  glyphLayout = new GlyphLayout();
}

Next, let's reuse the drawScore() method from our Snake game:

private void drawScore() {
  String scoreAsString = Integer.toString(score);
  glyphLayout.setText(bitmapFont, scoreAsString);
  bitmapFont.draw(batch, scoreAsString,) (viewport.getWorldWidth() - glyphLayout.width / 2, (4 * viewport.getWorldHeight() / 5) - glyphLayout.height / 2);
}

Finally, what we can do is extract the actual drawing code from the render() method into its own draw() method:

private void draw() {
  batch.setProjectionMatrix(camera.projection);
  batch.setTransformMatrix(camera.view);
  batch.begin();
  drawScore();
  batch.end();
}

Excellent! Let's run our project and see the results:

Scoring

Perfect, a bit small on the font size. However, remember we are using the default font. Later on, we will explore using our fonts!

We now have a game; however, it is rather lacking in the art department. Luckily, our game artist has just delivered the assets for the game!

Here is a selection of the assets we will use!:

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

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