Generic Scrolling Game

In this assignment, you'll be implementing a simple arcade game, like the one shown below.

The user controls an image (U) on the left edge of the screen, that can be moved up and down. Images are created on the right edge of the screen, and these scroll toward the user's image on the left edge. There are some images that the user tries to get (G), and there are other images that the user tries to avoid (A). The user earns a score, shown next to the title of the game, and the game ends when some condition is reached.

And the rest is up to you!

You get to choose the game's theme/story, by choosing the title, images, distribution of images, game speed, scoring function, and game-over condition. And, of course, you can do more if you like, as long as your game still fits the description given above. (Be sure to choose a theme for your game that is appropriate for a general audience!)

Small prizes and great honor will be bestowed upon the authors of the games we like best.

Start thinking now about ideas for the game you'll be creating. Whatever theme you choose, you must at least choose something. If your game is as lame as the one in the screenshot shown above, you will not receive full credit.

You may find this assignment to be fairly challenging in places. Make sure you leave yourself enough time to make your game interesting, as well as functional.


Reference

Location Class
Location(int row, int col)
int getRow()
int getCol()
boolean equals(Location other)

Color Class
Color(int red, int green, int blue)
int getRed()
int getGreen()
int getBlue()
boolean equals(Color other)

Grid Class
Grid(int numRows, int numCols)
int getNumRows()
int getNumCols()
Color getColor(Location loc)
void setColor(Location loc, Color color)
String getImage(Location loc) //returns null if empty
void setImage(Location loc, String imageFileName) //pass null image in order to remove an image
void setTitle(String title)
void pause(int milliseconds)
int checkLastKeyPressed() //returns -1 if no key pressed since last call


Exercises

Download and unzip ScrollingGame.zip, which contains all the files you will need for this assignment.

  1. Open Game.java. All the code you write for this assignment will go in this file.

    Game has several fields. The grid field holds the grid used to store and display images. The userRow field keeps track of which row the user-controlled image appears in, on the left edge of the grid. msElapsed keeps track of the total number of milliseconds that have elapsed since the start of the game. timesGet keeps track of the total number of times the user has gotten the things they're supposed to get in the game (collided with the images you want to hit). timesAvoid keeps track of the total number of times the user has been hit by the things they're supposed to avoid.

    The constructor has already been implemented for you, although you are encouraged to change the dimensions of the grid, the initial value of userRow, and the name of the image used to show the user.

    If you construct a new Game, you'll see a single image appear on the left edge of the grid window. The lame images "user.gif", "get.gif", and "avoid.gif" have been provided for you to use in your testing, but you must eventually replace them with images that are appropriate for your game's theme.


  2. Look at Game's play method, which has already been implemented for you. This method serves as the game's engine. Every 100 milliseconds, it handles a key press (if any), sometimes scrolls all images to the left and populates the right edge with new images, updates the title (to show the current score), and increments msElapsed. This repeats until the game is over.

    Your job in this assignment will be to implement the methods called by play. We'll start with handleKeyPress.

    Complete the handleKeyPress method. Write the following line of code to check for a key press:

    int key = grid.checkLastKeyPressed();

    If the user pressed the up arrow (key == 38), move the user's image up one row (unless the user is already in the top row). Likewise, if the user pressed the down arrow (key == 40), move the user's image down one row (unless the user is already in the bottom row). Either way, make sure to update userRow.

    You may test your code by executing

    Game.test();

    which simply constructs a new Game and calls its play method. You should be able to move the user image up and down, and you should be prevented from moving the image off the screen.


  3. Complete the populateRightEdge method, which should randomly place images that you want to get (such as "get.gif") and images that you want to avoid (such as "avoid.gif") in the rightmost column of the grid. Of course, you get to choose what "randomly" means here, as long as you use Math.random() somehow. Perhaps sometimes populateRightEdge shouldn't place anything. Perhaps sometimes it should place several images. Perhaps one image should appear often, while another image might appear only on rare occasions. (If you're unsure, you might just choose some arbitrary rule for now, and tweak it later.)

    Test your code as follows:

    Game g = new Game();
    g.populateRightEdge();
    

  4. Complete the scrollLeft method, which should move every image on the screen one column to the left. For example, if the grid initially appears as follows

    then after calling scrollLeft, it should appear as follows:

    Note that the G that was in the leftmost column has disappeared, and that an A has moved into the leftmost column. Note that the rightmost column will always be empty after scrollLeft is called. Finally, note that the user-controlled U should remain exactly where it was. (For now, you should assume that there is no image immediately to the right of the user, so you will not need to worry about the possibility of a collision in this exercise.)

    Hint: You might find it easier to first write a helper method that simply scrolls everything in a given row.

    Be sure to test your code by running the game.


  5. Complete the handleCollision method, which will be called whenever the user might collide with an image at the given location. Check if the image is null. If so, no collision has occurred, and there's nothing for you to do. If the image is something you want to get (such as "get.gif"), then increment timesGet. If the image is something you want to avoid (such as "avoid.gif"), then increment timesAvoid. Either way, remove the image at that location by setting it to null.

  6. There are two ways that the user can collide with an image. An image may scroll left into the user. Or the user may move up or down into an image. Therefore, we'll need to call handleCollision in both scenarios ...

    In the scrollLeft method, before doing any scrolling, call the handleCollision method. (Hint: If the user is about to get hit by something, in what location would that something be, immediately before scrolling?)

    In the handleKeyPress method, call handleCollision, passing the location that the user is about to move into. (Hint: Don't place the user's image in the new location until after you've called handleCollision.)

    Test your code by playing your game, making sure that it behaves reasonably.


  7. The fields timesGet and timesAvoid should each influence either the score, or the game-over condition, or both. For example, maybe getting something good increases the score, hitting something bad decreases the score, and the game ends after a set amount of time. Or alternatively, maybe getting something good increases the score, and hitting a certain number of bad things ends the game. Or alternatively, maybe the score depends only on how long the user has stayed alive, and the user dies when they've hit more bad things than good things. There are many possibilities here.

    Complete the getScore method, which should return the current game score. In determining the score, you may use timesGet, timesAvoid, and msElapsed.

    Then modify updateTitle to show the title of your game. (You're welcome to show other statistics in the title, in addition to the score.)

    Test that the score now updates correctly, as you play your game and collide with images.


  8. Complete the isGameOver method, which should return true when the game should end. This may be a function of timesGet, timesAvoid, and msElapsed. Be sure to test that your game ends at the correct moment.

  9. At this point, you've completed the code for this assignment. If you haven't already done so, work on the theme of your game, with appropriate images, title, etc.