CS21 Lab6: Blame it on the rain (yeah, yeah)

Due 11:59pm Tuesday, March 01, 2011

In this lab you will write a graphical game, in the file rain.py, in which a player attempts to stop rain drops (circles) from hitting the bottom of the screen. The goal of this lab is to give you more practice using functions, as well as give practice using an indefinite loop.

As in Lab 05, the key data in your program will be a list of circles, with one circle for each rain drop currently on the screen. You will use an indefinite loop to create rain drops at random locations near the top of the screen, and animate the rain as it gradually falls toward the bottom. The player earns points by clicking on a rain drop; when the player clicks a rain drop, you should undraw and stop animating that rain drop.

Here are some screen shots of my sample solution as I am playing:

The start:A few seconds later:The drops are falling:
 
Ooooh, I clicked one:They're getting low:Game over:

Below we suggest several functions that you should write to help implement your game. As usual, you should write these functions and then extensively test them in main. After you know that they work, you can remove your test code and write the main function of your program.



1. Create a raindrop

Write a function createDrop(window) that creates a new rain drop. It should take the following parameter:

  1. window: A GraphWin object.
Your createDrop function should create a new rain drop (a Circle) at a random location near the top of the window and draw it in the window. My createDrop function always creates rain drops of radius 9, but you may use a different (or varying) radius if you want. This function should return the rain drop it creates. Test your function by creating a window and an (initially) empty list of drops in main, use createDrop to create rain drops, and append those drops to the list.

Hint: You can use the randrange function from the random library to get a random integer from a given range. To use this, you can put the statement:

    from random import randrange
near the top of your program.



2. Moving raindrops

Write a function moveDrops(drops, dx, dy) that moves the rain drops the specified amounts in the x and y directions. This function is like jumpAlien in Lab 05; the movement is not animated and the moveDrops function should not use sleep().

The moveDrops function has the following parameters:

  1. drops: A list of Circle objects, the rain drops on the screen.
  2. dx: The distance to jump in the x-direction.
  3. dy: The distance to jump in the y-direction.

The moveDrops function should not return anything. Once you have written this function, create some drops in main and use moveDrops to move them to test the correctness of the moveDrops function. Once you confirm that moveDrops is correct, use a loop in main and Python's sleep function (in main) to animate the drops so they fall gradually toward the bottom of the screen. To use the sleep function you will need to import it from the time library:

    from time import sleep



3. Testing for the end of the game

The game ends when any rain drop hits the bottom of the screen. To help determine this, write a function noneOffBottom(window, drops) that takes two parameters:

  1. window: A GraphWin object.
  2. drops: A list of Circles representing unclicked rain drops on the screen.
The noneOffBottom function should return True if all drops are still above the bottom of the screen, but return False if any drops reach (or go beyond) the bottom of the screen.

Once you've written noneOffBottom, test it in main by using it as the condition in an indefinite (while) loop, ending the game when any rain drops reach the bottom of the screen.

4. Clicking on rain drops

When a user clicks on a rain drop, you should undraw that rain drop and remove it from the list of visible rain drops so that it is no longer animated and no longer ends the game if it hits the bottom of the screen.

To help determine if a rain drop has been clicked, write a function intersects(p, c) that takes two parameters:

  1. p: a Point object.
  2. c: a Circle object.
The function intersects should return True if the point p is within the circle c, and False otherwise. A point is within a circle if the distance between the point and the circle's center is less than or equal to the radius of the circle. This can be computed as follows. Given:
  dx = p.getX() - c.getCenter().getX()
  dy = p.getY() - c.getCenter().getY()
p intersects c if (dx*dx + dy*dy) is less than or equal to (c.getRadius()*c.getRadius()). (This is just a regular distance computation, with both sides squared.)

As usual, test your intersects function inside main before continuing your implementation. To test this, you might consider using getMouse or checkMouse in a loop and printing whether or not the Point from the mouse click intersects a rain drop.


5. Putting it all together

Once you've implemented and tested the above functions, you should have some list of rain drops that are animated down the screen in an indefinite loop, with the game ending when any rain drops hit the bottom of the screen. You can turn this into a game as follows:

  1. Near the top of the loop, occasionally use the createDrop function to add a drop to the screen. You can do this by using an accumulator variable to count the number of times the loop has run and adding a drop, e.g., every 100 times through the loop.
  2. Use the <window>.checkMouse() function to learn about mouse clicks from the user. checkMouse is like getMouse except that checkMouse does not wait for a mouse click. If the mouse has been clicked since the last check, checkMouse returns the Point of the mouse click location. If there has not been a mouse click, checkMouse returns None.
  3. If a user clicks the mouse, use the intersects function to check if that point intersects any visible rain drops. If it intersects a rain drop, undraw the drop and remove it from the list of rain drops in the game.
  4. Add a Text object that displays the score of the game. To keep track of the score, you'll need an additional accumulator variable that you increment when the player successfully clicks a drop, and use the accumulator to help update the Text's text.

Submit

Once you are satisfied with your program, hand it in by typing handin21 in a terminal window.