Firing Missiles


Next, I enable the ship to fire missiles. When the player presses the spacebar, a missile fires from the ship's cannon and flies off in the direction the ship faces. The missile should destroy anything it hits, but to keep things simple, I save the fun of destruction for another version of the program.

The Astrocrash04 Program

The Astrocrash04 program allows the player to fire missiles by pressing the spacebar. But there's a problem. If the player holds down the spacebar, a stream of missiles pours out of the ship, at a rate of about 50 per second. I need to limit the missile fire rate, but I leave that issue for the next version of the game. Figure 12.11 shows off the Astrocrash04 program, warts and all.

click to expand
Figure 12.11: The missile fire rate is too high.

Updating Ship's moved() Method

I update Ship's moved() method by adding code so that a ship can fire missiles. If the player presses the spacebar, I create a new missile:

       # fire missile if spacebar pressed       if self.screen.is_pressed(games.K_SPACE):           Missile(self.screen, self.get_xpos(), self.get_ypos(), self.get_angle()) 

Of course, in order to instantiate a new object from the line Missile(self.screen, self.get_xpos(), self.get_ypos(), self.get_angle()), I need to write a little something . . . like a Missile class.

The Missile Class

I write the Missile class for the missiles that the ship fires. I start by creating class variables and class constants:

 class Missile(games.Sprite):     """ A missile launched by the player's ship. """     image = games.load_image("missile.bmp")     sound = games.load_sound("missile.wav")     BUFFER = 40     VELOCITY_FACTOR = 7     LIFETIME = 40 

image is for the image of a missile—a solid, red circle. sound is for the sound effect of a missile launching. BUFFER represents the distance from the ship that a new missile is created (so that the missile isn't created on top of the ship). VELOCITY_FACTOR affects how fast the missile travels. And LIFETIME represents how long the missile exists before it disappears (so that a missile won't float around the screen forever).

I start the class constructor with the following lines:

     def __init__(self, screen, ship_x, ship_y, ship_angle):         """ Initialize missile sprite. """ 

It may surprise you that the constructor for a missile requires values for the ship's x-and y-coordinates and the ship's angle, which are accepted into the ship_x, ship_y, and ship_angle parameters. The method needs these values so that it can determine two things: exactly where the missile first appears and the velocity components of the missile. Where the missile is created depends upon where the ship is located. And how the missile travels depends upon the angle of the ship.

Next, I play the missile-firing sound effect:

         Missile.sound.play() 

Then, I perform some calculations to figure out the new missile's location:

         # convert to radians         angle = ship_angle * math.pi / 180         # calculate missile's starting position         buffer_x = Missile.BUFFER * math.sin(angle)         buffer_y = -Missile.BUFFER * math.cos(angle)         x = ship_x + buffer_x         y = ship_y + buffer_y 

I get the angle of the ship, converted to radians. Then, I calculate the missile's starting x-and y-coordinates, based on the angle of the ship and the Missile class constant BUFFER. The resulting x and y values place the missile right in front of the ship's cannon.

Next, I calculate the missile's velocity components. I use the same type of calculations as I did in the Ship class:

         # calculate missile's velocity components         dx = Missile.VELOCITY_FACTOR * math.sin(angle)         dy = -Missile.VELOCITY_FACTOR * math.cos(angle) 

Finally, I initialize the new sprite. I also make sure to give the Missile object a lifetime attribute so that the object won't be around forever.

         # create the missile         self.init_sprite(screen = screen, x = x, y = y,                            dx = dx, dy = dy, image = Missile.image)         self.lifetime = Missile.LIFETIME 

Then, I write a moved() method for the class. Here's the first part:

    def moved(self):        """ Move the missile. """        # if lifetime is up, destroy the missile        self.lifetime -= 1        if not self.lifetime:            self.destroy() 

This code just counts down the life of the missile. lifetime is decremented. When it reaches 0, the Missile object destroys itself.

In the second part of moved(), I include the familiar code to wrap the missile around the screen:

       # wrap the missile around screen       if self.get_top() > SCREEN_HEIGHT:           self.set_bottom(0)       if self.get_bottom() < 0:           self.set_top(SCREEN_HEIGHT)       if self.get_left() > SCREEN_WIDTH:           self.set_right(0)       if self.get_right() < 0:           self.set_left(SCREEN_WIDTH) 

I see that the preceding code is repeated three different times my program. I'll definitely be consolidating it later.




Python Programming for the Absolute Beginner
Python Programming for the Absolute Beginner, 3rd Edition
ISBN: 1435455002
EAN: 2147483647
Year: 2003
Pages: 194

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net