13.4 Creating Your Own Video Game

By now, you should have a good understanding of event-driven programming using the turtle module. We will finish this chapter by pulling everything together to create a simple video game—our own version of the old Space Invaders game, in which aliens appear in the sky and you must shoot them with a laser cannon before they reach the ground. In our game, however, drones will appear in the sky rather than aliens.

FIGURE 13.4 shows a screenshot of the game in action. In the figure, notice the three main objects that we will implement to develop our video game. At the bottom center of the window is the laser cannon, which is the usual turtle triangle. The drones are the enemies, and the small circles are the bombs that have been shot from the laser cannon. These three things will become our main classes: LaserCannon, Drone, and Bomb. Each of these classes inherits from the Turtle class, so we can control each element of our game as a Turtle. The different appearance of each object comes from using the turtle shape method that allows us to use image files and even shapes you draw yourself to represent a turtle.

A Python Turtle Graphics window shows a screenshot of game with 7 turtles in the screen.

FIGURE 13.4 Drone invaders.

© 2001–2019 Python Software Foundation. All Rights Reserved.

The next step is to identify the capabilities of each of our classes. The LaserCannon must be able to do two things:

  •    Aim at Drones.

  •    Fire Bombs.

A Bomb must be able to do three things:

  •    Move in the direction it was fired.

  •    Detect when it hits a Drone.

  •    Detect when it disappears out of the window.

A Drone must be able to do two things:

  •    Move from the top of the screen to the bottom.

  •    Detect when it reaches the bottom of the screen.

This high-level design is captured in FIGURE 13.5. As is standard UML practice, the abstract BoundedTurtle and its two abstract methods, move and remove, are italicized. Also as is standard practice with UML, in the Drone class, the static variable droneList and the static method getDrones are underlined.

A class diagram of drone invaders design is shown.

FIGURE 13.5 Drone invaders design.

13.4.1 The LaserCannon Class

Let’s look at the implementation of the LaserCannon class in more detail (see LISTING 13.9). This class should look somewhat familiar to you after studying the bouncing turtles example from the previous section. The LaserCannon will serve as our initial turtle, so it will create the window for all the other turtles that come later. In the _ _init_ _ method, we create a turtle and set up three callback functions: aim, shoot, and quit. A mouse click causes the aim method to be called. The aim method turns the laser cannon toward the position of the cursor where the mouse was clicked. The shoot method is called when the user presses the “s” key. The shoot method is very short: It just creates a new Bomb. As you will see later in Listing 13.12, the constructor for Bomb takes care of the rest of the work.

Image

LISTING 13.9 The LaserCannon class

13.4.2 The BoundedTurtle Class

The BoundedTurtle class is an abstract class that will be the superclass of both the Drone and Bomb classes. The difference between a regular Turtle and a BoundedTurtle is that the BoundedTurtle knows when it is outside the window. When the turtle is outside the window, it disappears.

LISTING 13.10 shows the code for the BoundedTurtle class. In the outOfBounds method, the statement xPos, yPos = self.position() is equivalent to two statements that get the x and y coordinates of the turtle separately. The turtle position method returns a tuple, but the assignment statement unpacks the tuple and assigns the corresponding elements to the variables on the left-hand side. The outOfBounds method returns True or False depending on whether the turtle has gone outside its boundaries.

Image

LISTING 13.10 Bounded turtles can check whether they are out of bounds

The BoundedTurtle class defines two abstract methods: move and remove. The Bomb and Drone classes will need to define these methods, and Python will use polymorphism to determine which class’s version of the method to call depending on the object used to call the methods.

13.4.3 The Drone Class

The next class we will implement is the Drone class. Our drones need to be able to move down the screen, and they need to be able to remove themselves from the game when they are hit by a Bomb.

As in the bouncing turtle simulation, we will keep track of all drones so that when a bomb moves, we can test whether it has hit any of the drones. We will use a static variable droneList to keep track of all the drones that are alive.

To keep things simple, we want only one method to add or remove drones from the droneList. We will perform this task in the Drone constructor. When a new drone is created, we append the new drone to the list. When a drone is hit by a bomb, we set the _ _alive instance variable for that drone to False.

Because the Bomb class needs to know which drones it can blow up, it needs to get a list of all the “live” drones. To do this, the Drone class will provide a static method called getDrones to return a list of live Drones. Like static attributes, static methods are independent of objects. Static methods are useful when you have a method that belongs inside a class but does not apply to any instance of the class.

LISTING 13.11 shows the code for the Drone class. Notice that no self parameter appears in the formal parameter list of the static method getDrones. Also notice that we use a new decorator, @staticmethod, to create a static method. The @staticmethod decorator tells the Python interpreter that there is no need to pass an instance variable as an implicit parameter to the function getDrones. Instead, we call the method using the class name, as in Drone.getDrones(), without needing an instance of the Drone class.

Image

LISTING 13.11 The Drone class

Drone.getDrones returns all the live drones by constructing a new list created from the instances of Drone where _ _alive is True.

The other Python construct that is part of the getDrones method is the list comprehension on line 7. List comprehension provides a concise way to create a list without using a for loop with an append inside it. SESSION 13.4 illustrates some uses of list comprehensions. The first example shows it is legal to apply Python operators to the variable you are using to create the list.

Image

SESSION 13.4 Using list comprehensions

The getDrones method on lines 6–7 of Listing 13.11 uses a list comprehension and is equivalent to the getDrones method shown here:

Image

Notice two important points about the _ _init_ _ method. First, it is the only method allowed to modify the droneList. This restriction ensures that we avoid the situation in which one callback method could be adding a drone to the list while another is trying to remove a drone from the list. This could happen if a bomb hit a drone at the same time that another drone was being created.

Second, notice that the Drone’s remove method sets the value of _ _alive to False and hides the turtle. In the constructor, we use a list comprehension to filter out the dead drones every time a new drone is created. This performance improvement keeps the list nice and short.

Also notice the conditional statement on lines 13–14. This statement checks whether the 'Drone.gif' file has been loaded. If it has been loaded once, it is not necessary to load it again because the addshape method just loads a list of shapes that works for all the turtles in the same window.

The move method checks whether the drone is out of bounds. If the drone stays in bounds, the timer is reset so that the drone will move again in 200 milliseconds. If the drone is out of bounds, the drone is removed and the timer is not reset.

The remove method marks the drone as dead and hides it so it is no longer seen. By setting

_ _alive = False, the drone stays on the list (until another drone is created), but will not be included in any calculations involving bombs that are shot from the laser cannon.

13.4.4 The Bomb Class

Our final class, Bomb, is no more complicated than the bouncing turtle. A bomb is created with an initial heading corresponding to the direction in which the cannon is pointing. Once the bomb is created, it continues moving in that direction. If it runs into a drone, the bomb explodes, the drone is marked as dead, and the bomb hides itself and ceases to move. LISTING 13.12 shows the Bomb class. In the distance method, we calculate the distance between the bomb and each Drone using the math.dist method (lines 24–27).

Image

LISTING 13.12 The Bomb class

13.4.5 Putting All the Pieces Together

To put together all the pieces of the game and start things running, we will create one final class, DroneInvaders, which will be the main application. LISTING 13.13 provides the code for the DroneInvaders class. The main task of this class is to create a LaserCannon object and to set up a timer to add drones to the playing field at regular intervals. These tasks are implemented in the play method.

Image

LISTING 13.13 Putting it all together

To play the game, we execute the two commands shown in SESSION 13.5. Of course, these commands should be added to the bottom of the .py file with all of the class definitions so we can run everything with a single command. At the top of the .py file, you should include import statements for turtle, random, math, and abc.

Image

SESSION 13.5 Running the drone invaders game

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

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