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.

Piper game

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

  1. 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, and Pillow modules. After installation you should be able to execute import pygame in the shell without any error. If you have trouble installing pygame, please visit drop-in hours or consult with Smith or the course assistants.
  2. Download the program starter file
  3. 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!