On this page:
Video Lessons
Instructions
Practice Problems
Problem 1: N Bullets
5.1 Introduction
5.1.1 Submission format
5.1.2 World requirements
5.1.3 Ships
5.1.4 Bullets
5.1.5 Java and math
5.1.6 Tick-tock On The Clock
5.1.7 Local variables
5.1.8 A note about randomness
5.1.9 Suggested constants
5.1.10 Yikes, This Sure Is A Lot!
7.7

Assignment 5: A Game

Goals: Design a game, by designing the data and methods as appropriate for a real-world problem.

Related files:
  LibraryExample.java  

Video Lessons
Instructions

This assignment is long. Start early.

Make sure you follow the style guidelines that we enforce. For now the most important ones are: using spaces instead of tabs, indenting by 2 characters, following the naming conventions (data type names start with a capital letter, names of fields and methods start with a lower case letter), and having spaces before curly braces.

You will submit this assignment by the deadline using the online submission system. You may submit as many times as you wish. Be aware of the fact that close to the deadline the system may slow down to handle many submissions - so try to finish early.

There will be a separate submission for each problem - it makes it easier to grade each problem, and to provide you with feedback for each problem you work on.

The submissions will be organized as follows:

Practice Problems

Work out these problems on your own. Save them in an electronic portfolio, so you can show them to your instructor, review them before the exam, use them as a reference when working on the homework assignments.

Problem 1: N Bullets

5.1 Introduction

You are going to design a game called N Bullets, based on the game 10 Bullets.

N Bullets is a game in which ships fly across the screen and the player shoots bullets at them from the center of the bottom of the screen. When a bullet and ship collide, both are instantly destroyed. The bullet, however, is replaced by a group of bullets that fly out to hit other ships. The game ends when the player run out of bullets and no more bullets are on screen.

Your game will use the javalib.funworld library, which provides an implementation of Worlds and bigBang similar to what was used in Fundies 1. Read the documentation carefully for more information.

5.1.1 Submission format

You may find it overwhelming to keep all of your code within one file. To make your code more manageable, you may submit a zip archive for this assignment instead of a single file. If you are more comfortable submitting as a single file, though, that is also fine.

5.1.2 World requirements
5.1.3 Ships
5.1.4 Bullets
5.1.5 Java and math
5.1.6 Tick-tock On The Clock

This style of programming is called a fluent interface.

As you may have noticed, a lot has to happen in one tick (bullets and ships have to move, collisions need to be handled, ships may be spawned, etc.). To make this manageable, we recommend you design methods that use the current (this) world and produce a new world, where one of those steps have been taken, and a new world is returned. You can then chain those together to in your onTick method. Using this methodology, it should look something like this (with much better naming, of course):

// advance the world by one tick: do step one, then step two, then step three, // and then step four public MyTowerDefenseClass onTick() {
return this.doStepOne()
.doStepTwo()
.doStepThree()
.doStepFour();
}

An added benefit of designing this collection of methods is, of course, the ability to test each step of your code independently.

As a note of caution, beware that you’re calling dependent operations in the right order. For example, the order in which you choose to remove off-screen components and handle ship/bullet collisions could affect the results of the game.

5.1.7 Local variables

You will almost certainly want to use local variables for this assignment.

Be cautious, because some programms use local variables as an excuse for not using helper methods. Remember, one task per method.

Let’s say we were computing the average of a list, and returning 0 if the list was empty:

public int average() {
if (this.length() == 0) {
return 0;
} else {
return this.sum() / this.length();
}
}

The problem, of course, is the length is being computed twice. One way to get around this would be to use a helper method:

public int average() {
return this.averageHelper(this.length());
}
 
public int averageHelper(int length) {
if (length == 0) {
return 0;
} else {
return this.sum() / length;
}
}

Why did the programmer choose to compute the sum in the helper and not in the outer method and pass it to the helper?

This is fairly verbose for such a simple operation, however. Instead, we can use a local variable:

public int average() {
int length = this.length();
if (length == 0) {
return 0;
} else {
return this.sum() / length;
}
}

This local variable could have been called something besides length.

As in ISL, local variables should be used to avoid duplicate computation, clarify what expressions mean, and contain simple computations another method wouldn’t need to use. Proper usage of local variables, also like in ISL, is a judgement call.

5.1.8 A note about randomness

There are two ways to generate random numbers in Java. The easiest is to use Math.random(), which generates a double between 0 (inclusive) and 1 (exclusive). You can multiply this number by some integer to make it bigger, then coerce to an int to produce a random integer in the range you wish. However, this is not easily testable: you’ll get different random values every time.

The better way to generate random numbers is: First, import java.util.Random at the top of your file. Next, create a new Random() object, and use its nextInt(int maxVal) method, which will give you a random integer between zero (inclusive) and maxVal (exclusive).

This is known as a "pseudorandom number generator", since the numbers aren’t really random if they can be reliably repeated...

The reason this is better is because there is a second constructor, new Random(int initialSeed), which has the property that every time you create a Random with the same initial seed, it will generate the same "random" numbers in the same order every time your program runs. You should therefore design your world classes with two constructors:

5.1.9 Suggested constants

While you are welcome to tweak the game to create gameplay you enjoy (so long as you adhere to all of the above specifications), here are the constants we used that we know will generate decent gameplay:

5.1.10 Yikes, This Sure Is A Lot!

Yes, it is, but don’t worry, you can do it. A big part of being able to succeed with this assignment is to keep track of what data represents what, how to organize it, and what you will need to do with it. As always, sticking to the design recipe and fleshing out your wishlist in advance is the best way to go about handling daunting programs. To help you out, we’ve started an informal wishlist of tasks your program must be able to do:

All of these directly imply that your program also needs to do the following:

To begin, we recommend fleshing out this wishlist and storing it somewhere you can easily access, and determing which classes each task should belong to. Then, you can add the method stubs to each of the classes, and write examples and tests before you begin to program. Give each method its own test function, and comment them out. As you implement each method, you can uncomment that method’s test function, and that way you can test the whole program as you go.