In this lab, you will explore principles from event-based programming and create a simple video game that roughly approximates the 70s arcade game Asteroids. Specifically, we will use timer events, keyboard button events, and collision detection.
As the gateway into the final project, this lab will review concepts we've learned all semester: lists, objects and object-oriented design, classes, inheritance, top-down design, and more.
shapes.pyfrom Project 10.
mosaic.py). This will be the background artwork for your video game!
self.screen = turtle.Screen(). This creates an object of type
Screen, which represents the
turtlecanvas. Call the
setup()method on the
Screenobject, passing in your desired canvas size (e.g.
TurtleInterpreterhas been initialized!
getScreenfor the screen instance variable.
drawto the constructor. Make it an instance variable of
Shape. Update your function calls in
drawto refer to your
getScreenthat calls the
getScreenmethod from your
TurtleInterpreterinstance variable. This method will pass the
Screenobject from the
TurtleInterpreterto your game.
Game: Background artwork
terpin your file (this includes removing calls to hold()!). You should only work with
Shapeobjects in your function.
Shapeobject, call its
getScreenmethod and assign the screen object that it returns to a variable. For example:
sky = shapes.Square(distance=1000, fill=True) screen = sky.getScreen()
Note if using
mosaic: You most likely have a
mosaic function that calls a
tile function in a nested loop.
mosaic(before the loops): e.g.
sqr = shapes.Square()(filling in any required parameters). We're calling it 'dummy' because we aren't actually going to draw it, we just want to use it to get the
getScreenon your 'dummy' shape object (e.g.
sqr), assign the screen object that it returns to a variable.
Note about the purpose of
screen: We want to pass the
Screen object from where it was created in the first shape in your scene to the game. Here is a summary of its path:
TurtleInterpreter constructor) ->
Game) -> self.screen (
setupBackgroundmethod. It should call your scene function to draw your background artwork (e.g. in
setupBackgroundreturn the screen object returned by artwork scene function.
setupBackgroundmethod and assign the return value to an instance variable in
self.screen). This should be the first thing that you do in the constructor.
mainfunction outside of the class. Create a new
Gameobject, then call its run method (see next step) to start the game.
if __name__ == '__main__'top-level code at the bottom of the file that calls the
runmethod to your
def run(self): ''' Turns the tracer animations on (but speeds up animations) and starts the main game loop. ''' # Make sure animations are on but fast turtle.tracer(True) turtle.speed(0) # Let's go! self.screen.mainloop()
game.py. If everything is working so far, you should simply see your background artwork scene drawn to the screen (no game elements yet).
Game: Player Turtle
Game. It should
turt = turtle.Turtle())
turtle.register_shape('rocketship.gif') # Make the rocketship image available to turtle turt.shape('rocketship.gif') # Set the turtle icon to the rocketship image
makePlayermethod from your constructor (after you setup the background artwork), assigning the output to an instance variable (e.g.
Game: Interactive player control
We're going to make the player turtle (rocketship) move under keyboard control!
Gameconstructor. You might wish to create optional parameters for these, giving them default values of 20 and 10, respectively.
up: Move the player forward by its speed
down: Move the player backward by its speed
left: Turn the player left by its rotation rate
right: Turn the player right by its rotation rate
setupEventsmethod that creates your game events. Add keyboard callback events to the four movement methods you just created. Here, callback means that we will instruct our game to move our player by calling one of movement methods when we press the appropriate keyboard button. To add a callback, we call the
onkeymethod of the
Screenobject. It has the following syntax:
self.screen.onkey(<Method name>, <String of keyboard button>). For example
self.screen.onkey(self.up, "Up")for moving the player up. To assign to the four arrow keys, use the strings: "Up", "Down", "Left", "Right".
quitfunction when the user presses the "q" key.
listenmethod on your screen object so that it will start calling the movement methods when you press the arrow keys.
setupEventsat the end of the constructor.
In this task, we will create a number of enemy turtle objects that move randomly.
def placeEnemyRandomly(self, turt):, which will move the
turtobject to random coordinates within the enemy bounds you defined in (1).
def makeEnemies(self, n):It should
turt.shape('square')) and set the color to a color of your choosing via the usual means.
self.placeEnemyRandomlyon each enemy.
Gameconstructor, assign the return value to an instance variable (e.g.
self.enemies). Either hard code
n(number of enemies) or make it an (optional) parameter in your constructor.
Game: Enemies on the move
In this task, we will create a timer event to randomly move the enemies over time.
def moveEnemiesRandomly(self):. It should set each enemy's position to the current position plus a small random (x, y) offset.
setupEvents, create a timer that will automatically call
moveEnemiesRandomly50 msec after the game starts. The syntax is:
self.screen.ontimer(<method name to call>, <int: wait time in msec>).
ontimeronly will call the
moveEnemiesRandomlymethod ONCE 50 msec in the future, but we want to continue moving them every 50 msec indefinitely. To do this, add an identical timer at the end of
moveEnemiesRandomly. Make sure that you understand why we're doing this before continuing.
Game: Collision detection
We will create another timer event to have the enemy take an action when the player collides with it.
def checkForCollisions(self):. It should
placeEnemyRandomlyon the enemy that the player collided with.
setupEventsto check for collisions.