Homework 1: Flappy Box

In this homework, you will implement "Flappy Box," a simplified version of Flappy Bird in Java.

Objectives

  • Apply object-oriented programming principles to design and implement a game
  • Review and practice Java programming concepts
  • Improve code comprehension and coding skills
  • Practice adhering to coding standards and style guidelines
  • Gain familiarity with our homework structure and submission process

Important Dates

EventDayDateTime
ReleaseThuAug 2909:00 AM ET
DueThuSep 0505:00 PM ET

Homework Description

Flappy Box is a 2-dimensional side-scrolling game where the player controls a yellow square (box). The objective is to guide the box through a series of obstacles (pipes) without touching them, using the space bar to control its movements. The score tracks the player's progress as they navigate the obstacles, increasing every time an obstacle is successfully passed. The game ends when the box hits an obstacle, falls off the bottom of the canvas, or flies too high to reach the top of the canvas.

You will use an Object-Oriented approach for designing and implementing the game. The game will be written in multiple Java files, each containing a different "class". Additionally, the program will use Princeton's StdDraw.java library.

The code should be well-organized, easy to read, and exhibit elements of object-oriented, structured, and modular programming. Moreover, it must comply with the provided checkstyle rules and specifications.

Homework 1 is an excellent way to start this Data Structures course. It is both fun and challenging, allowing you to demonstrate your understanding of the Java programming language and practice your problem-solving skills. The game is an engaging way for you to apply the skills you have acquired throughout the Gateway Computing: Java course.

Starter Code

Download the starter code from the following link: hw1.zip.

The starter code is a zip file named hw1-starter.zip. You must unzip this file. After unzipping, you will get a folder called hw1-starter. Open this folder as an IntelliJ project.

A common mistake students make when opening the homework projects is that they open a different folder, such as the folder containing the starter code or the source (src) folder inside of it! Make sure you open the root folder as an IntelliJ project.

Tasks

Once the project is open, explore the files in the src/main/java/hw1 folder. You should do this through the Project View panel in IntelliJ. This panel appears on the left side of the IntelliJ window. If you don't see it, you should be able to toggle it open by going to the View menu, and then selecting Project from Tool Windows.

There are several folders and files in the starter code. The structure is consistent with how build tools like Maven and Gradle organize Java projects. However, in this course, you will not be using any of those build tools. You will be working primarily with files inside the src/main/java/ and src/test/java/ folders.

Source files

To open a file, you can double-click on it in the Project View panel. This will open the file in the editor window. Explore the source files in the following order:

  1. Block.java: A block is a game object with a rectangular bounding box. This file is completely implemented.

  2. Sprite.java: A Sprite is a Block that can move. This class is also fully implemented.

  3. Box.java: A Box is a square Sprite with a fixed length. This class is missing the implementation for the intersects operation. You should implement this later. For now, just explore the codebase.

  4. FallingBox.java: A FallingBox is a Box that falls with acceleration due to gravity. This class is partially implemented. You should update the move method to ensure the FallingBox does not fall off the (bottom of the) screen. You will do this later!

  5. FallingBoxDemo.java: A demo where a FallingBox falls from the top of the screen. Run this demo by clicking on the green play icon next to the public class FallingBoxDemo { statement; select "Run 'FallingBoxDemo.main()'". You should see a window open with the title "Standard Draw". The window will have a sky blue background and include a yellow square "falling down". To stop the demo, you should close the "Standard Draw" window. Later, once you update the FallingBox.move() operation, you should also update the FallingBoxDemo.runGameLoop() method to end (i.e., set isGameOver to true) when the FallingBox reaches/falls off the (bottom of the) screen.

  6. FlappyBox.java: A FlappyBox is a FallingBox that can jump. The jump operation is left for you to implement. You will do this later!

  7. FlappyBoxDemo.java: A demo where a FlappyBox can jump when the space key is pressed. Run this file; it should look similar to FallingBoxDemo. As the FlappyBox is falling, press the space key and look over the console in IntelliJ. You should see the word "Jump!" printed.

  8. Pipe.java: A Pipe is a game object composed of multiple Boxes. Pipes are obstacles in the path of the FlappyBox. Each pipe has a hole, an opening space, as large as two boxes. The player must guide the FlappyBox to pass through the pipes' openings. The Pipe class is fully implemented.

  9. MovingPipeDemo.java: Run this demo file. You should see the green pipes moving from right to left on the screen. You should explore the code to understand how the pipes are generated and moved. The MovingPipeDemo class is a good example of how to use the Pipe class in a game.

  10. GameConstant.java: A class containing all the constants used in the game. This is a utility class and should not be instantiated (that is why it has a private constructor).

  11. Game.java: The main class for the Flappy Box game. Most of the operations are left for you to implement (at a later time).

A note on StdDraw.java: The StdDraw.java library is a simple library for drawing graphics in Java. It is used in this homework to create a window and draw shapes on it. You do not need to understand how StdDraw.java works. You can think of it as a "black box" that allows you to draw shapes on the screen. You can find more information about StdDraw.java here.

A note on coordinates: All game objects exist in a standard X-Y coordinate plane. When a new Block is created, the top-left X and Y coordinates are specified, and then all other coordinates are calculated relative to it. For instance, the following image shows the corners of a 75x75 Block created at (100, 300):

From this, you can see that as a block falls, you'll decreate the Y coordinate -- and if it jumps, you'll increase it.

Test files

Next, you will explore the test files located in src/test/java/hw1. We will teach you about testing later in this course. For the first homework, you do not need to have a deep understanding of how the tests work. You should only be able to run the tests.

  1. BlockTest.java: Open this file and click on the green play icon next to the public class BlockTest { statement. Then select "Run 'BlockTest'". This will run all the tests in this file. You should see a report in IntelliJ including the list of 9 tests in this file. There must be a green check mark next to each test.

  2. SpriteTest.java: Open this file and run the tests. All tests should pass. Notice a green play icon next to each test. If you want to run just one test, you can click on this icon and run it. For instance, try running only the test with the display name "Test initial speed is zero".

  3. BoxTest.java: Open this file and run the tests. Notice some of the tests fail because the intersects operation is not implemented yet. Go to the Box.intersects operation and change return false; to return true;. Then, run the tests in BoxTest. Notice the tests that were failing before are now passing. However, the implementation of Box.intersects is still incorrect! This is a good example to show that it is not necessarily the case that when a test passes, your implementation is correct. This is why we don't use such tests to auto-grade your submission. The tests provide preliminary feedback. A teaching assistant will always carefully review your submission and grade it.

  4. Further explore FallingBoxTest.java, FlappyBoxTest.java, and GameTest.java files. Run their tests and notice some tests fail as there are missing implementations in their corresponding classes. However, all the tests in PipeTest.java must pass as Pipe.java is already correctly implemented.

As you implement various operations in this project, use the provided tests to check your work. These tests also run when you submit your code to Gradescope. While not exhaustive, they offer a solid starting point to verify your implementation's correctness. For this homework, we've supplied the tests. In future assignments, you'll write your own—we'll teach you how in the coming weeks. We'll also have our own tests for each homework to evaluate your Gradescope submissions. These tests won't be shared with you!

Implementation

Now it is time to implement the game! I suggest the following plan:

  1. Implement FlappyBox.jump. When the jump operation is called, the flappy box must move up by the value of jumpVelocity. Moreover, you should reset the falling speed and acceleration to their corresponding initial values. You may want to look over the constructor of FallingBox to see how these values are initialized. Once the jump operation is implemented, run the tests in FlappyBoxTest and make sure they all pass. Moreover, run the FlappyBoxDemo and ensure the flappy box jumps when you press the space bar.

  2. Implement FallingBox.move. You should update the move method to ensure the FallingBox does not fall off the bottom of the screen. You should think about two things:

    • How can you detect if the FallingBox has reached the bottom of the screen? Hint: the y-coordinate of the bottom of the box would be 0 when it reaches the bottom of the screen.

    • How can you stop the FallingBox from falling further down? Hint: when an object is not moving, its speed is zero.

    Once the move operation is implemented, run the tests in FallingBoxTest and make sure they all pass. Moreover, run the FallingBoxDemo and ensure the falling box stops as it reaches the bottom of the screen. Additionally, update the FallingBoxDemo to stop the game loop once the FallingBox has reached the bottom of the screen.

  3. Implement Box.intersects. You should return true if this box intersects with the other box. You should think about various scenarios where two boxes can intersect. For instance, the two boxes might intersect partially or one might be entirely inside the other one. There are several tests provided in the BoxTest class. These tests are not exhaustive and do not account for all cases, but they should give you a good starting point. All the tests in the BoxTest class should pass if you implement the intersects operation correctly.

  4. Implement the operations of the Game.java. You can look at the demo classes (FallingBoxDemo, FlappyBoxDemo, and MovingPipeDemo) to find an initial implementation for most of the operations in the Game class. The game should adhere to these specifications:

    • The game begins with a canvas appearing on the screen. A "flappy box" is located on the left side, while several obstacles (pipes) are randomly generated and move from right to left.

    • During the game, the flappy box can be controlled by the player using the space bar key. Pressing the space bar will make the box jump.

    • The score, which is displayed at the top of the screen, tracks the player's progress as they navigate the obstacles. It increases every time an obstacle is successfully passed.

    • The game ends when the flappy box collides with an obstacle, such as a pipe. Hint: You might reasonably expect the intersects method to be transitive -- that is, pipe.intersects(flappyBox) to do the same thing as flappyBox.intersects(pipe). However, given that a Pipe is composed of multiple Boxes, with a gap in the middle, this is not the case. Carefully think about which of these method calls will account for this.

    • The game ends when the flappy box reaches the bottom of the canvas or flies too high to reach the top of the canvas.

    • After the game ends, a message displaying "game over" is shown over the canvas.

Discussion

Every homework will include a discussion section. The discussion section is an opportunity for you to reflect on the concepts you have learned and how they are applied in the homework. The discussion section is a critical part of the homework and will be graded.

You should write your answer in the README.md file. The README.md file is located at src/main/java/hw1/. You can open this file in IntelliJ by double-clicking on it in the Project View panel. This will open the file in the editor window. Please keep your answers brief and to the point.

Part I

Describe the following terms with examples from the source code of this game: Class, Object, Encapsulation, Abstraction, Data type, Composite data type, Method, Constructor, Instance variable, Local variable, Parameter, Return type, Inheritance, Type Hierarchy, Apparent type, Actual type, Is-a relationship, Has-a relationship, Method overloading, Method overriding, Static polymorphism, Dynamic polymorphism.

You can use the StdDraw.java library, along other classes in the game, as an example for some of the terms.

Part II

Provide examples of data structures used in the game. Explain why these data structures are used and how they help in the implementation of the game.

Part III

Provide an example of an algorithm used in the game. Explain how the algorithm works and how it helps in the implementation of the game.

Submission

In preparation, you must (1) run checkstyle to ensure your code is checkstyle compliant (if not, fix the styling issues). (2) Create a zip file containing the src folder (and all therein). (3) Submit the zip file to Gradescope.

Checkstyle

To run checkstyle, go to the View menu, and then select CheckStyle from Tool Windows. Next, select "cs226" from the "Rules" dropdown. Finally, click on "Check Project." (One of the buttons on the left side of the CheckStyle panel under the green play icon). If there are any issues, you should see them in the CheckStyle panel. You can double-click on an issue to navigate to the corresponding line in the editor window.

Make sure your code is checkstyle compliant before submitting.

Zip File

You must create a zip file containing the src folder (and all therein). You can usually do this by right-clicking on the src folder (outside of IntelliJ) and selecting "compress" or "zip" or "archive," etc.

You should submit the zip file to Gradescope. A common mistake students make is submitting the wrong file or the wrong folder. For example, they zip the root folder of the project hw1-starter instead of the src folder inside it. Make sure you zip the correct folder.

Gradescope

Go to course Canvas page and click on the Gradescope link. You will see an assignment called "Homework 1: Flappy Box." Click on this assignment and upload your zip file. You can submit as many times as you like. We will only grade the last submission.

Rubric

Teaching assistants will evaluate your submission using the following criteria:

  • Spec 1: The game is written in multiple Java files, each containing a different "class". It utilizes Princeton's StdDraw.java library. [0.5 points]

  • Spec 2: The game compiles without errors or warnings and runs smoothly without any delays or glitches. [1 point]

  • Spec 3: The game begins with a canvas appearing on the screen. A "flappy box" is located on the left side, while several obstacles (pipes) are randomly generated and move from right to left. [1 point]

  • Spec 4: The FallingBox.java file includes a correct implementation of the move operations. The FallingBox does not fall off the bottom of the screen. Moreover, the game loop of the FallingBoxDemo.java file stops when the FallingBox reaches the bottom of the screen. [1.5 points]

  • Spec 5: The FlappyBox.java file contains a correct implementation of the jump operation. The FlappyBox jumps when the space bar key is pressed and moves up by the value of jumpVelocity. The falling speed and acceleration are reset to their initial values. [1 points]

  • Spec 6: The Box.java file includes a correct implementation of the intersects operation. The operation returns true if this box intersects with the other box. The tests in the BoxTest.java file pass when the intersects operation is implemented correctly. [2 points]

  • Spec 7: During gameplay, the flappy box can be controlled by the player using the spacebar key. Pressing the spacebar will make the box jump. [1 point]

  • Spec 8: The score, which is displayed at the top of the screen, tracks the player's progress as they navigate the obstacles. It increases every time an obstacle is successfully passed. [1.5 point]

  • Spec 9: The game ends when the flappy box collides with an obstacle, such as a pipe. [1 point]

  • Spec 10: The game ends when the flappy box falls off the bottom of the canvas or flies too high to reach the top of the canvas. [1 point]

  • Spec 11: After the game ends, a message displaying "game over" is shown over the canvas. [1 point]

  • Spec 12: The code is well-organized, easy to read, and exhibits elements of object-oriented, structured, and modular programming. Moreover, it must comply with the provided checkstyle rules and specifications. [1 point]

  • Spec 13: The discussion questions in Part I accurately describe all requested terms with relevant examples from the game's source code. [5.5 points: 0.25 points per term]

  • Spec 14: The discussion questions in Part II provide appropriate examples of data structures used in the game, with clear explanations of their usage and benefits. [2 points: at least two examples; 1 point per example]

  • Spec 15: The discussion questions in Part III present a relevant algorithm example from the game, explaining its functionality and importance in the game's implementation. [1 points]

The total score for this homework is 22 points.