Video Games are fun!

This begins a series of lessons that highlight some important aspects of programming while being fun as well.

The game of asteroids is a simple and fun game that illustrates concepts from computer graphics, geometry, and trigonometry.

Each lesson is designed to allow the students to play with a small part of the program and extend it in some way.

The following lessons also introduce Tkinter programming which is a nice toolkit for doing Graphical User Interface design and implementation.

 

Asteroids!

The Asteroids video game was originally designed and written by the folks at Atari. It was released to the public in 1979. In the game the player controls a spaceship that navigates space and blows up asteroids by shooting at them.

When an asteroid is hit the player scores points and the asteroid splits into two smaller asteroids. The largest asteroids are worth 20 points. Each medium asteroid is worth 50 points. The smallest asteroids are worth 100 points each. When the spaceship hits a small asteroid it is obliterated into dust and it disappears completely from the game.

If an asteroid collides with the spaceship, the spaceship is destroyed, the asteroid that collided with it is destroyed (resulting in no points) and the player gets a new spaceship. The game starts with four spaceships total (the original game started with only three).

In the original game, there were flying saucers that would periodically appear. These UFOs would shoot at the ship and if the ship fired back and blew one up, there were 200 points awarded for hitting a large UFO and 1000 points awarded for blowing up a small UFO. The version of the game described in these lessons does not include UFOs, but it could be extended to included them if you want to write the code!

Pictured here is an example of a computer game that when completed will play the game of Asteroids! You can click on the picture below to get a copy of some code that will get you started writing your own asteroids game.

Click on this picture below and copy the code to the clipboard. Then open Wing IDE 101 and create a new program file. Paste the code into the window. Save it as asteroids.py. Run the program by clicking the Debug button to see what is implemented so far.

The code that was provided is not complete. To complete the game, you'll have to implement the extensions described in this and the next few lessons. But first, you need to become familiar with Python programming by examining the code you just copied.

We'll start from the top of the file and cover the code in the order that it is executed.

When writing a program, you can't possibly write all the code yourself. Python programmers import code from other modules so they can use that code in their programs. Python comes with a large number of modules that all have documentation to describe what they do and how to use them. You import code from a module by writing import statements at the top of your program.

from turtle import *
import tkinter.messagebox
import tkinter
import random
import math

These import statements import code from five modules. The turtle module implements turtle graphics. Turtle graphics emulates a turtle on a sandy beach. When the turtle drags its tail it leaves a trail. This is a paradigm (a way of thinking about) implementing vector graphics. You should examine the turtle graphics documentation to learn what a turtle can do when using turtle graphics.

The tkinter modules implement GUI (graphical user interface) programming. Graphical User Interfaces are programs that display a window like the one above.

The random module makes it easy to generate random numbers. You need random numbers to build an interesting game.

The math module implements functions like square root and cosine and sine.

After the import statements are four variables that are assigned values: screenMinX, screenMinY, screenMaxX, and screenMaxY. The values -500 and 500 are stored as values and named with these names. Variables are just like named memory locations in your calculator. You can store values so they can be easily retrieved earlier.

After the four variables comes two class definitions. These class definitions define what a Spaceship looks like and how it acts in the program and what an Asteriod looks like and does as well. We'll skip to after these class definitions for now.

The intersect function is a function that returns True if two objects intersect (like an Asteroid and the Ship) and False if they do not intersect. It is not used for now so we'll come back to it later.

Finally the main function is where everything gets started. The main function is called on the last line of the program. Calling a function is just like calling a function in Mathematics. You write the name of the function to call it followed by parentheses and then the information you want to pass to a function. Nothing is passed to the main function on the last line of the program. It is just called to get everything started.

The first few lines build the GUI window and get a Turtle Graphics session started.

 # Start by creating a RawTurtle object for the window. 
 root = tkinter.Tk()
 root.title("Asteroids!")
 cv = ScrolledCanvas(root,600,600,600,600)
 cv.pack(side = tkinter.LEFT)
 t = RawTurtle(cv)
 screen = t.getscreen()
 screen.setworldcoordinates(screenMinX,screenMinY, 
    screenMaxX,screenMaxY)
 screen.register_shape("rock3",((-20, -16),(-21, 0), 
    (-20,18),(0,27),(17,15),(25,0),(16,-15),(0,-21)))
 screen.register_shape("rock2",((-15, -10),(-16, 0), 
    (-13,12),(0,19),(12,10),(20,0),(12,-10),(0,-13)))
 screen.register_shape("rock1",((-10,-5),(-12,0),
    (-8,8),(0,13),(8,6),(14,0),(12,0),(8,-6),(0,-7)))
 screen.register_shape("ship",((-10,-10),(0,-5),(10,-10),(0,10)))
 screen.register_shape("bullet",((-2,-4),(-2,4),(2,4),(2,-4)))
 frame = tkinter.Frame(root)
 frame.pack(side = tkinter.RIGHT,fill=tkinter.BOTH)
 t.ht()

The root variable above is the root window of the GUI program. The cv variable is the canvas where the turtle graphics displays.

The screen is the turtle graphics screen. The world coordinates is the coordinate system for the turtle graphics area (i.e. -500 to 500 in the X and Y directions).

The shapes that are registered are the shapes of each of the elements of the game: asteroids (i.e. rocks), a spaceship, and the bullets.

Finally a frame is just a container for other tkinter widgets. A widget is an element of a GUI program like a button. The quit button is placed within the frame with this code.

 def quitHandler():
       root.destroy()
       root.quit()
 quitButton = tkinter.Button(frame, text = "Quit", \
       command=quitHandler)
 quitButton.pack()

The code above tells Python to call the quitHandler function when the quit button is pressed while Asteroids is running.

The line below creates a spaceship for the application.

ship = SpaceShip(cv,0,0,(screenMaxX-screenMinX)/2+screenMinX,
(screenMaxY-screenMinY)/2 + screenMinY)

Now You Try It

When a spaceship is created it uses the ShaceShip class. This is the code that starts class SpaceShip. The class definition says what a spaceship is and what a spaceship does. A spaceship is a turtle because it inherits from RawTurtle (which is a type of Turtle). You can review the turtle module documentation to see what a turtle is. In addition to being a turtle, it can also be told to move, fire its engine, and we can get its current X and Y trajectory (called dx and dy).

You can customize your program by picking a color for your ship. Turtle graphics has lots of colors predefined, so you should be able to find something you like. However, pretty much any color can also be created by writing

self.color("#ffff00")

This creates the color yellow using hexadecimal numbers. Each color that can be displayed is composed of a red, green, and blue component. Numbers from 0 (00 in hexadecimal) to 255 (ff in hexadecimal) are used to indicate how much red, green, and blue should be included in a color. So full red and green mixed makes yellow.

Play with this. Pick a color for your spaceship and for your asteroids. Run the program to see that your colors are working and that you like them.

Playing the Game

Playing an asteroids game means moving the ship and the asteroids around the screen. This code creates a list of five big asteroids for the game.

 asteroids = []
         
 for k in range(5):
   dx = random.random() * 6 - 3
   dy = random.random() * 6 - 3
   x = random.random() * (screenMaxX - screenMinX) + screenMinX
   y = random.random() * (screenMaxY - screenMinY) + screenMinY
 asteroid = Asteroid(cv,dx,dy,x,y,3)
 asteroids.append(asteroid)

To make the game animated, a play function is repeatedly called to move the game's objects around on the screen. The following code accomplishes this by setting a timer to call the play function. When the play function is called, another timer is set to call it again. In this way, the play function is called over and over again to move the spaceship and asteroids.

 def play():
   # Tell all the elements of the game to move
   ship.move()
 
   for asteroid in asteroids:
     asteroid.move()
   # Set the timer to go off again in 5 milliseconds
   screen.ontimer(play, 5)
 # The following line sets the timer to call the play function
 # the first time only. 
 screen.ontimer(play, 5)

We'll be making changes to this code to play the rest of the game as we work to complete this game.

Responding to Input

For the game to be interesting, we must get some input from the user. The keypad will work nicely for this. We'll have the number 4 turn the spaceship to the left and the number 5 start the spaceship moving. Here is the code that does this.

 def turnLeft():
 	ship.setheading(ship.heading()+7)
 
 # This tells the turtle graphics when a 4 is pressed to
 # call the turnLeft function
 screen.onkeypress(turnLeft,"4")
 
 def forward():
 	ship.fireEngine()
 
 # This tells the turtle graphics when a 5 is pressed to 
 # call the forward function when immediately calls the 
 # fireEngine function on the ship.
 screen.onkeypress(forward,"5")

Now You Try It

Write the code so when 6 is pressed that the ship turns to the right. Calling the heading function on the ship returns its heading in degrees (from 0 to 360 degrees). Calling the setheading function on the ship sets a new heading for the ship. The ship is also a turtle. So, heading and setheading are functions that are defined on turtles. Adding 7 degrees to the turtle heading turns the ship to the left. How do you make it turn to the right?

Write the code and then run it to see that it works correctly.

Have Extra Time?

By changing the register shape calls you can design your own space ship and asteroids. The rock3 asteroid is the largest of the asteroids. The rock2 and rock1 you can't see yet.

Before making any new designs, be sure to copy the line you are changing and comment out the copy by adding a # sign to the beginning of the line. That way you are saving a copy of what you had to start with.

What's Next?

In the next lesson, we'll discover how to fire Photon Torpedoes from our spaceship!