Homework 7: Piper Game Part 1 Due Friday November 17, 11:59PM EST
This is a two part homework assignment. You’ll be working on the first part of the “Piper Game” this week (that’s what’s written on this page), and for HW 8 you will complete your implementation of the game. This is the smaller piece of the assignment, so although the due date is officially Friday, November 17th (following the convention of homework assignments being due on Friday), I recommend trying to complete this part by Tuesday, November 14th to give yourself more time to complete the second part of the assignment! The second part of the assignment will be available on the 14th.
Background
In this homework you will be implementing the “Piper Game” using Object-Oriented Programming (OOP) techniques. The sand piper must race the clock to collect as many clams on the beach without getting wet. A screencast of a run of the game is shown below.
For this homework you will begin to extend the starter file so that next week, you can create a fully fledged game. Make sure to read the entire assignment thoroughly and follow the instructions exactly. Everything will come together when you implement the full game!
Recall that two benefits of OOP are encapsulation/abstraction and reuse. We will explore both by specializing a provided Entity
class to implement the different entities in the game, e.g. the piper, and implementing methods to abstract the operations (like moving or rendering) on those entities. As an example of successful abstraction you should be able to change how you store the position and size of the game entities (i.e., change the instance variables of the Entity
class) without changing any code within your game loop!
Inheritance
You need to learn about the concept of inheritance before completing this homework. Please watch the short video below about inheritance before you start programming!
Getting Started
- We will be using the PyGame module to implement some of the mechanics of game play. Install the PyGame module much as you did for the
pytest
,numpy
, andPillow
modules. After installation you should be able to executeimport pygame
in the shell without any error. If you have trouble installingpygame
, please visit drop-in hours or consult with Smith or the course assistants. - Download the program starter file
- Download the two images needed for the game: the piper and the clam. These images must be saved to the same directory as your program file. NOTE: you won’t use these for HW 7, but it will be helpful to have them downloaded for HW 8!
Part 1: Entity
The Entity
class serves as the base class for all of the other game elements. All entities have a PyGame Rect
instance variable that is used to track their position and size. A Rect
is an object in the graphics library pygame that stores rectangular coordinates. It is initialized using four arguments: left
, top
, width
, and height
.
You will need to add a method collide
to the Entity
class that has one parameter (in addition to self
), another Entity
, and returns True
if the two entities overlap. By implementing this method in Entity
, it will be inherited by all of the other games entities that derive from Entity
. For example:
>>> e1 = Entity(0, 0, 50, 50)
>>> e2 = Entity(25, 25, 50, 50)
>>> e1.collide(e2)
True
>>> e3 = Entity(75, 75, 25, 25)
>>> e1.collide(e3)
False
With two rect objects r1
and r2
, you can use the colliderect
method (r1.colliderect(r2)
) to determine if the two rectangles have any overlap on the screen. This code will be useful as you implement your collide
method. Remember that one of the Rect
instances is self.rect
and the other is the argument’s rect
attribute. You can see the pygame documentation for colliderect
here.
Part 2: Player
The Player
class should derive from Entity
. Its __init__
method should take no parameters other than self
and should initialize the player in the top-left corner of the screen (NOTE: this is position (0, 0)) with a size of 50×50. Recall that a derived class should invoke its base class’s initializer with super().__init__
. Since Player
inherits from Entity
it can access the rect
instance variable via self.rect
.
Creating a Player in play_game
Once you have implemented the above, create a single Player
object in the play_game
function (in the section with the “Initialize Player, Wave and Clams” comment).
Part 3: Clam
The Clam
class should derive from Entity
. Its __init__
method should take no parameters other than self
and should initialize the clam randomly in the right-half of the screen (the part of the screen touched by the wave) with a size of 30×30. Thus each clam should have a random x-coordinate between 0.5 * SCREEN_WIDTH
and SCREEN_WIDTH - 30
, and a random y-coordinate between 0 and SCREEN_HEIGHT - 30
. Pick the coordinates using the random.randint
function. Like Player
, it’s __init__
method should call super().__init__
.
Generating Clams
You’ll need to re-generate a list of clams multiple times throughout the program - that means that it’s a good idea to write a function to do it, so that you don’t have to re-write the same code multiple times! Write a function generate_clams
that takes no parameters and returns a list containing NUM_CLAMS
clams. Create the clams using the Clam()
constructor.
generate_clams
should take no parameters. It is a function, not a method (so you don’t need self
), and you can access NUM_CLAMS
as a gloabl variable without using a parameter.
Creating Clams in play_game
Call your generate_clams
function to create a list of clams in the play_game
function (in the section with the “Initialize Player, Wave and Clams” comment).
Part 4: Wave
We will model the wave as a blue rectangle the same size as the screen that periodically moves back and forth over the right half of the screen - like a wave (that is, some or all of the rectangle will “hang off” the right side of the screen at any moment in time and not be displayed). The Wave
class should inherit from Entity
. Its __init__
method should take no parameters other than self
. It should call super().__init__
, and should initialize the wave at x
= 0.75 * SCREEN_WIDTH
and y
= 0
(the middle of its movement) with a size of SCREEN_WIDTH
×SCREEN_HEIGHT
.
Creating a Wave in play_game
Create a single Wave
object prior to the main game loop (in the section with the “Initialize Player, Wave and Clams” comment).
Looking forward
For homework 8, you’ll implement the fully operational game - the purpose of this assignment is to get the constructors for your classes in good shape and get practice instantiating objects before you start working on the visual component. If homework 8 has been released, I strongly recommend getting started early!
Submitting
Submit your hw7.py
file on gradescope!