Chapter 11. Collisions, Sound Effects and Supporting Different Versions of Android

By the end of this chapter, we will have a fully working and beeping implementation of the Pong game. We will start the chapter off by looking at some collision detection theory which will be put in to practice near the end of the chapter. We will also learn about how we can detect and handle different versions of Android. We will then be in a position to study the SoundPool class and the different ways we use it depending on the Android version the game is running on. At this point, we can then put everything we have learned into producing some more code to get the Pong ball bouncing and beeping as well as put the finishing touches on the game.

In summary, we will cover following topics:

  • Study the different types of collision detection
  • Learn how to handle different versions of Android
  • Learn how to use the Android SoundPool class
  • Finish the Pong game

Mind your head!

Handling collisions

As collision detection is something we will need to implement for all the remaining projects in this book I thought a broader discussion beyond that which will be required for Pong might be useful. Furthermore, I am going to use some images from the 5th game project to visually demonstrate some topics around collision detection.

Collision detection is quite a broad subject. So here is a quick look at our options for collision detection and in which circumstances different methods might be appropriate.

Essentially, we just need to know when certain objects from our game touch other objects. We can then respond to that event by bouncing the ball, adding to the score, playing a sound or whatever is appropriate. We need a broad understanding of our different options, so we can make the right decisions in any particular game.

Collision detection options

First, here are a few of the different ways we can use mathematics to detect collisions, how we can utilize and when they might be useful.

Rectangle intersection

This type of collision detection is straightforward and used in lots of circumstances. If at first, this method seems imprecise, keep reading until you get to the multiple hitboxes section further on.

We draw an imaginary rectangle; we can call it a hitbox or bounding rectangle, around the objects we want to test for collision and then mathematically test the rectangle's coordinates to see if they intersect. If they do, we have a collision.

Rectangle intersection

Where the hitboxes intersect we have a collision. As we can see from the previous image this is far from perfect. But in some situations, it is sufficient, and its simplicity makes it very fast, as demonstrated in the next project, Bullet Hell. To implement this method all we need to do is a test for the intersection using the x and y coordinates of both objects.

Note

Don't use the following code. It for demonstration purposes only.

if(ship.getHitbox().right > enemy.getHitbox().left  
   && ship.getHitbox().left < enemy.getHitbox().right ){
   // Ship is intersecting enemy on x axis
   // But they could be at different heights

   if(ship.getHitbox().top < enemy.getHitbox().bottom  
         && ship.getHitbox().bottom > enemy.getHitbox().top ){
         // Ship is intersecting enemy on y axis as well
         // Crash
   }
}

The above code assumes we have a getHitbox() method that returns the left and right horizontal coordinates as well as the top and bottom vertical coordinates of the given object. In the code above, we first check to see if the horizontal axes overlap. If they don't then there is no point going any further if they do we then check the vertical axis. If they don't it could have been an enemy whizzing by above or below. If they overlap on the vertical axis as well then, we have a collision.

Note that we can check the x and y-axis in either order provided we check them both before declaring a collision.

Radius overlapping

This method is also checking to see if two hitboxes intersect with each other but as the title suggests it does so using circles instead. There are obvious advantages and disadvantages. Mainly that this works well with shapes more circular in nature and less well with elongated shapes.

Radius overlapping

From the previous image, it is easy to see how the radius overlapping method is inaccurate for these objects and not hard to imagine how for a circular object like a football or perhaps a decapitated zombie head bouncing on the floor it would be perfect.

Here is how we could implement this method.

Note

The following code is also for demonstration purposes only.

// Get the distance of the two objects from 
// the edges of the circles on the x axis
distanceX = (ship.getHitBox.centerX + ship.getHitBox.radius) - (enemy.getHitBox.centerX + enemy.getHitBox.radius;

// Get the distance of the two objects from 
// the edges of the circles on the y axis
distanceY = (ship.getHitBox.centerY + ship.getHitBox.radius) - (enemy.getHitBox.centerY + enemy.getHitBox.radius;

// Calculate the distance between the center of each circle
double distance = Math.sqrt
   (distanceX * distanceX + distanceY * distanceY);

// Finally see if the two circles overlap
if (distance < ship.getHitBox.radius + enemy.getHitBox.radius) {
    // bump
}

The code again makes some assumptions. Like we have a getHitBox() method that can return the radius as well as the central x and y coordinates.

Note

If the way we initialize distance: Math.sqrt(distanceX * distanceX + distanceY * distanceY); looks a little confusing; it is simply using Pythagoras' theorem to get the length of the hypotenuse of a triangle which is equal in length to a straight line drawn between the centers of the two circles. So then in the last line of our solution, we test if distance < ship.getHitBox.radius + enemy.getHitBox.radius we can be certain that we must have a collision. That is because if the center points of two circles are closer than the joint length of their radii they must be overlapping.

Crossing number algorithm

This method is mathematically more complicated. But it is perfect for detecting when a point intersects a convex polygon. The method breaks an object down into straight lines and tests each point of each object to see if it crosses a line. The number of crosses is added and if the number is odd (for any single point) then a hit has occurred.

Crossing number algorithm

Note

This is perfect for an Asteroids clone or for a spaceship flying over the top of some jagged mountain range. If you would like to see the code for a full implementation of the crossing number algorithm in Java, look at this tutorial on my Website: http://gamecodeschool.com/essentials/collision-detection-crossing-number/

We won't be using this solution for the projects in this book.

Optimizations

As we have seen, the different collision detection methods can have at least two problems depending on which method you use in which situation. The problems are

  1. Lack of accuracy
  2. Drain on CPU power

The first two options (rectangle intersection and radius overlap) are more likely to suffer from inaccuracy and the second (crossing number algorithm) is more likely to cause a drain on the Android device's power and cause slowing down of the game.

Here is a solution to each of those problems.

Multiple hitboxes

The first problem, a lack of accuracy can be solved by having multiple hitboxes per object. We simply add the required number of hitboxes to our game object to most effectively 'wrap' it and then perform the same rectangle intersection code on each in turn.

Neighbour checking

This method allows us to only check objects that are in the approximate same area as each other. It can be achieved by checking which "neighborhood" of our game a given two objects are in and then only performing the more CPU intensive collision detection if there is a realistic chance that a collision could occur.

Supposing we have 10 objects that each need to be checked against each other then we need to perform 10 squared (100) collision checks. But if we do neighbor checking first we can significantly reduce this number. In the very hypothetical situation in the next diagram, we would only need to do an absolute maximum of 11 collision checks, instead of 100, for our 10 objects, if we first check to see if objects share the same sector/ neighborhood.

Neighbour checking

Implementing this in code can be as simple as having a sector member variable for each game object that represents its current neighborhood, then looping through the list of objects and just checking when they are in the same sector. This optimization can be used with any type of hitbox.

Best options for Pong

Now that we know our collision detection options, we can decide the best course of action in our current game. All our Pong objects are rectangular (or square), there are no extremities or irregularities on any of them.

This tends to suggest we can use a single rectangular hitbox for the bat and the ball and we will also need to prevent the ball leaving the screen.

The RectF intersects method

To make life even easier the Android API as we have seen has a handy RectF class that doesn't only represent our objects (bat and ball) but also our hitboxes. It even has a neat intersects() method that basically does the same thing as rectangle intersection collision detection code we have hypothesized previously. So, let's think about how to add collision detection to our game.

We already use a RectF called mRect in each of the Bat and the Ball classes. Not only this but we have even already coded a getRect method in each to return a reference to each object's RectF.

A solution is at hand and we will see really soon how we implement it. As we will want to play a beep sound every time there is a collision, let's look at how to create and play sound effects first.

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

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