Run update21, if you haven't already, to create the cs21/labs/10 directory. Then cd into your cs21/labs/10 directory and create the python programs for lab 10 in this directory.
For this lab we will use object-oriented programming and the Zelle graphics library to create a single player version of the Pong video game. The game consists of a ball and a paddle, as shown below. The ball will bounce around the window and the player must move the paddle up and down to try to hit the ball and keep it in play. If the ball ever gets past the paddle, the game ends. In order to make the game a little more challenging, after every fifth time the player hits the ball, its speed will increase slightly.
Please create your solution for this game incrementally.
The paddle class, defined in the file paddle.py, allows the user to create a paddle at a given point, with a given width, height, and color. The constructor should take care of drawing the paddle in the given window.
The full paddle class should have the following methods. See below for details and a suggested order to implement and test the methods. Note that when defining the Paddle class, you'll need to put (object) after class Paddle to get it work properly (as shown next).
class Paddle(object) | | __init__(self, window, center, width, height, color, speed) | The constructor for the Paddle class takes the following parameters: | window A GraphWin object | center A Point object for the location of the paddle | width An integer for the width of the paddle | height An integer for the height of the paddle | color A string for the color of the paddle | speed An integer for the speed of the paddle | and should draw the paddle in the given graphics window | | __str__(self) | pretty-format the paddle object | | getLeftEdge(self) | return x coord of left edge of paddle | | getP1(self) | return top-left Point of paddle | | getP2(self) | return bottom-right Point of paddle | | increaseSpeed(self, percent) | increase paddle speed by percent amount | | moveOnce(self, direction) | move paddle once according to speed and direction. | make sure paddle doesn't leave the window
Once you have these two methods written, add some test code to your class. Create two paddles, make sure they are drawn correctly, and the data looks correct when you print each object.
Once you have these methods written, add more test code to your class. Make sure each method is working correctly before moving on.
At this point you should have a working Paddle class. To mimic the game we will eventually create, it would be nice to put a while loop in your test code, to allow the user to move the paddle up and down. Here's an example of using the Zelle graphics checkKey() method to check for keyboard input from the user (assuming we already have a Paddle object stored in the variable p1):
while True: key = gw.checkKey() if key == "Escape": break elif key == "Up": p1.moveOnce(key) elif key == "Down": p1.moveOnce(key) elif key == "f": p1.increaseSpeed(.2) elif key == "s": p1.increaseSpeed(-.2) if key != None: print(p1)
This video shows a simple test of the Paddle class (with two paddles; lines are drawn for illustrative purposes and not required):
The ball class, defined in the file ball.py, allows the user to create a ball at a given point, with a given size and color. The constructor should take care of drawing the ball in the given window, and should also pick random numbers for the ball's initial speed in the x and y directions. Use numbers that make the animation look good and the game fun.
The full ball class should have the following methods. See below for details and a suggested order to implement and test the methods. Note that when defining the Ball class, you'll need to put (object) after class Ball to get it work properly (as shown next).
class Ball(object) | | __init__(self, window, center, radius, color) | The constructor for the Ball class takes the following parameters: | window A GraphWin object | center A Point object for the location of the ball | radius An integer for the radius of the ball | color A string for the color of the ball | and should draw the paddle in the given graphics window | and pick random speeds | | __str__(self) | pretty-format the ball object | | checkContact(self, paddle) | This method returns True when the circle representing the ball | is contacting the given paddle. Otherwise it returns False. | | getRightEdge(self) | get x coord of right edge of Ball object | | getSpeedX(self) | get speed in x direction | | getSpeedY(self) | get speed in y direction | | goFaster(self) | speed up the ball a little bit | | goSlower(self) | slow down the ball a little bit | | moveOnce(self) | move ball once according to its speed, take care of bouncing off window edges |
Once you have these two methods written, add some test code to your class. Create two balls, with different sizes and colors, and make sure they are drawn correctly. Print each ball object and make sure the data looks correct.
Once you have these methods written, add more test code to your class. Print the ball objects and make sure the data looks correct.
For example, suppose the y coordinate of the top of the ball is -2, meaning it has moved 2 pixels into the top wall. We would then change the y speed (multiply by -1) and move the ball 4 pixels down (since it should have bounced off the top wall).
Or suppose the x coordinate has gone 3 pixels past the right edge of the window. We then change the x speed of the ball (multiply it by -1) and move the ball 6 pixels back to the left.
Here is the pseudo code for this method:
- check if ball's right edge is past paddle's left edge - if so, check if ball's center is between top and bottom edge of paddle - if also so, it's in contact with the paddle, so you should: * change the speed in the x direction (multiply it by -1) * move the ball until right edge is no longer past paddle's left edge * return True - if the above aren't so, return False
This one is similar to the moveOnce method, except we are testing against the paddle instead of the right wall of the graphics window. This method should also return a True or a False.
To make sure you have a working Ball class, we still need to test the moveOnce and checkContact methods. First check the moveOnce method. To mimic the game we will eventually create, add a while loop in your test code, to allow the user to watch the ball objects move and bounce off the walls.
Here's an example of moving the ball objects and using the Zelle graphics checkKey() method to check for keyboard input from the user (assuming we already have a Ball object stored in the variable b1):
while True: b1.moveOnce() key = w.checkKey() if key == "Escape": break elif key == "f": b1.goFaster() elif key == "s": b1.goSlower() sleep(0.01) print(b1)
This video shows a simple test of the Ball class:
Once you know moveOnce works, add a Paddle to the above code and make sure the ball bounces off the paddle. An easy test would be to make a very large paddle on the right side of the window.
Once you are satisfied that the Ball class is working
properly, move on to implementing the game itself.
Open a new file called pong.py and implement the full game, using both the Ball and Paddle classes.
Here is a list of things the game should do:
This video shows another version of the program:
Once you are satisfied with your program, hand it in by typing handin21 in a terminal window.