Firing the Cannons

After the user input, the bullets are the most complex portion of the game. Keeping track of 50 sprites that can move in four different directions and may or may not be alive at the current moment is tricky. The cannons are about to get a lot more exciting. In this section, you add the bullets and write the code that handles how and when the cannons fire their volleys of shots.

Follow these steps:

1. Add the code in Listing 9-14 to the GameView constructor. This code handles the new bullets the cannons shoot. The number of bullets onscreen is limited to 50 to keep things simple. There are two arrays: one contains the bullet sprites (bullets[]) and the other holding the list of bullets that aren’t currently in use (available_bullet[]).

Listing 9-14. Additions to the onCreate() method that handle the bullets.

available_bullet = new int[50];
for(int i = 0; i < 50; i++){
        available_bullet[i] = i;
}

bullets = new SpriteObject[50];
for(int i = 0; i < 50; i++){
        bullets[i] = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.bullet), 10, 10);
        bullets[i].setState(bullets[i].DEAD);
}

You declare an array of integers in which every bullet is available, because you know that none have been fired yet. The bullets sprites are initialized as well. You set their state to DEAD because you don’t want bullets to appear without having been fired.

2. Add the code in Listing 9-15 to the update() method. First, you set the available_bullet array equal to zero; this will make calculations easier as you go along. Then you create a very important variable: g = 0. g is used to specify which bullets are available and which aren’t.

Listing 9-15. Resetting the List of Available Bullets

for(int f = 0; f < 50; f++){
        available_bullet[f] = 0;
}

int g = 0;

3. Immediately after clearing the array, place the code from Listing 9-16 into the update() method.

Listing 9-16. Handling Changes in Bullets

for(int i = 0; i < 50; i++){

if(bullets[i].getY() > 800 || bullets[i].getX() > 1280 || bullets[i].getY() < 0 || bullets[i].getX() < 0){
                bullets[i].setstate(bullets[i].DEAD);
        }

        for(int b = 0; b < boat_count; b++){
                if(bullets[i].collide(boat[b])){
                        boat[b].diminishHealth(1);
                        bullets[i].setstate(bullets[i].DEAD);
                }
        }
                
bullets[i].update(adj_mov);

        if(bullets[i].getstate() == bullets[i].DEAD){
                available_bullet[g] = i;
                g++;
        }

}

A loop goes through every bullet sprite. The first if statement checks to see if the bullet has left the screen; if it has, you set its state to DEAD. This means it can be reused as an available bullet in your next iteration. A for loop handles boat collisions. If the boat is hit, then its health goes down by one, and you destroy the bullet. Again, the bullet can now be reused. A simple update() call changes the location of the bullet based on its moveX and moveY.

If the bullet is dead, then you list it as an available bullet. If you look closely at the if statement, you notice that the first dead bullet is given the first spot in the available_bullet array, g is incremented, and the next dead bullet is given the next slot.

4. With the bullets ready to go, it’s time to worry about the firing mechanism. Fifty iterations of the update() function release a bullet from every cannon on the playing field. The code in Listing 9-17 performs these with a call to the new function createBullet(), which takes four arguments. Put this code into the update() method immediately after the code you’ve already added to the method.

Listing 9-17. Calculating When to Fire a Volley of Bullets

shooting_counter++;
if(shooting_counter >= 50){
        shooting_counter = 0;
        int round = 0;
        for(int i = 0; i < cannon_count; i++){
                if(cannon[i].getOrientation() == cannon[i].LEFT){
                        int x = (int)(cannon[i].getX());
                        int y = (int)(cannon[i].getY() + cannon[i].getBitmap().getHeight()/2);
                        createBullet(x,y,cannon[i].LEFT, round);
                        round++;
                }
                if(cannon[i].getOrientation() == cannon[i].RIGHT){
                        int x = (int)(cannon[i].getX() + cannon[i].getBitmap().getWidth());
                        int y = (int)(cannon[i].getY() + cannon[i].getBitmap().getHeight()/2);
                        createBullet(x,y,cannon[i].RIGHT, round);
                        round++;
                }
                if(cannon[i].getOrientation() == cannon[i].UP){
                        int x = (int)(cannon[i].getX() + cannon[i].getBitmap().getWidth()/2);
                        int y = (int)(cannon[i].getY());
                        createBullet(x,y,cannon[i].UP, round);
                        round++;
                }
        if(cannon[i].getOrientation() == cannon[i].DOWN){
                        int x = (int)(cannon[i].getX() + cannon[i].getBitmap().getWidth()/2);
                        int y = (int)(cannon[i].getY() + cannon[i].getBitmap().getHeight());
                        createBullet(x,y,cannon[i].DOWN, round);
                        round++;
                }
        }
}

This block of code creates the variable round, which tracks which bullet has been fired. The first cannon fires round one, the second cannon fires round two, and so on. The series of if statements uses the new getOrientation() function you created in SpriteObject.java. The x and y coordinates of the end of the barrel of each cannon are then passed to the createBullet() method. Getting the coordinates requires some calculations because you know the barrel is in the center of the cannon.

The mechanics of the bullets make even more sense in createBullet(), which you’ll write in the next section; the code in Listing 9-17 simply sends the necessary information to that method. Because you’ve initialized all the bullet sprites already, this doesn’t waste processing because you’re only updating the sprites.

5. To finish the update() method, make sure you have the calls to the various sprites’ update() functions as shown in Listing 9-18.

Listing 9-18. Including the Basic update() Functions

castle.update(adj_mov);
ground.update(adj_mov);
for(int i = 0; i < boat_count; i++){
        boat[i].update(adj_mov);
}        

}

The next section ties up the loose ends by handling game resets and firing bullets.

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

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