Moving the Ship


In the next version of the program, I get the ship moving. The player can press the Up Arrow key to engage the ships engines. This applies thrust to the ship in the direction the ship is facing. Since there's no friction in this simple game, the ship keeps moving based on all of the thrust the player applies to it.

The Astrocrash03 Program

When the player engages the ship's engines, the Astrocrash03 program changes the velocity of the ship based on its angle (and produces an appropriate sound effect too). Figure 12.10 illustrates the program.

click to expand
Figure 12.10: The ship can now move around the screen.

Importing the math Module

The first thing I do is import a new module at the top of the program:

 import math 

The math module contains a bunch of mathematical functions and constants. But don't let that scare you. I use only a few in this program.

Adding Ship Class Variables

I create a class constant, VELOCITY_STEP, for altering the ship's velocity:

     VELOCITY_STEP = .03 

A higher number would make the ship accelerate faster, a lower number would make the ship accelerate more slowly.

I also add a new class variable, sound, for the thrusting sound of the ship:

     sound = games.load_sound("thrust.wav") 

Updating Ship's moved() Method

Next, I add code to the end of Ship's moved() method to get the ship moving. I check to see if the player is pressing the Up Arrow key. If so, I play the thrusting sound:

         # apply thrust based on up arrow key         if self.screen.is_pressed(games.K_UP):             Ship.sound.play() 

Now, when the player presses the Up Arrow key, I need to alter the ship's velocity components (the Ship object's dx and dy attributes) based on the angle of the ship. For example, if the ship's angle is 0 degrees (it's facing straight up), then I need to decrease the object's dy attribute. Conversely, if the ship's angle is 90 degrees (it's facing to the right), then I need to increase the object's dx attribute. And if the ship is at 45 degrees (it's facing diagonally up and to the right), then I need to decrease the object's dy attribute and increase it's dx attribute equally. Of course, every angle requires its own adjustments. So, how can I figure out how much to change each velocity component based on the angle of the ship? Well, the answer is trigonometry. Wait, don't slam this book shut and run as fast as your legs can carry you, screaming incoherently. As promised, I use only two mathematical functions in a few lines of code to figure this out.

To start the process, I get the angle of the ship, converted to radians:

             # get velocity component changes based on ship's angle             angle = self.get_angle() * math.pi / 180 # convert to radians 

A radian is just a measure of rotation, like a degree. Python's math module expects angles in radians (while livewires works with degrees) so that's why I need to make the conversion. In the calculation, I use the math module constant pi, which represents the number pi.

Now that I've got the ship's angle in radians, I can figure out how much to change each velocity component using the math module's sin() and cos() functions, which calculate an angle's sine and cosine. The following lines calculate how much the object's dx and dy attribute values should change based on the ship's angle and VELOCITY_STEP:

             add_dx = Ship.VELOCITY_STEP * math.sin(angle)             add_dy = -Ship.VELOCITY_STEP * math.cos(angle) 

Next, I calculate the object's new dx and dy values using add_dx and add_dy:

             # add current velocity and velocity change to get new velocity             dx, dy = self.get_velocity()             new_dx = dx + add_dx             new_dy = dy + add_dy 

Then, I set the object's velocity with these new values:

             # set new velocity             self.set_velocity(new_dx, new_dy) 

All that's left to do is handle the screen boundaries. I use the same strategy as I did with the asteroids: the ship should wrap around the screen. In fact, I copy and paste the code from Asteroid's moved() method to the end of Ship's moved() method:

       # wrap the ship 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) 

Although this works, copying and pasting large portions of code is usually a sign of poor design. I'll revisit this code later and find a more elegant solution.

TRAP

Repeated chunks of code bloat programs and make them harder to maintain. When you see repeated code, it's often time for a new function or class. Think about how you might consolidate the code into one place and call or invoke it from the parts of your program where the repeated code currently lives.




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