Assignment 4: Adventure Game
Create a reusable framework for an adventure video game. Within a
package named "adventure", define base classes Player, Monster, and Game.
This package will form a reusable framework; clients of the framework will
instantiate objects of these classes or subclasses. Design the classes
to be extended. Clients can extend the adventure.Player, adventure.Monster,
and adventure.Game classes and use their client-specific subclasses instead
of the base classes.
Ground Rules
There is always exactly one Player per Game. There may be an unlimited
number of Monsters, possibly of different subclasses. By default,
a game consists of Monsters appearing occasionally at random, chasing,
and attacking the Player. Each time the Player is attacked, he or
she loses a random number of "health points" and the Monster also loses
a random number of health points. When a Monster's health points
drops to 0, it is removed from the game. By default, when the Player's
health points drop to 0, the player loses and the game is over. By default,
if a player defeats 100 monsters, he or she wins the game and the game
is over.
Together, the Game, Player, and Monster classes should implement these
ground rules in a way which distributes responsibility logically among
the classes and allows clients to override the rules in their own subclasses.
UI
The Game should manage a window (either an applet or a standalone frame)
with a graphical representation of the Player and Monster(s); each Player
and each Monster should manage its own appearance via a draw() method.
(See the ChaseGame.java sample for an example of drawing multiple objects.)
Monsters can attack the Player only when they are touching the Player.
You an use any reasonable method for making the Monsters chase the Player,
and letting the user move the Player. The graphics can be very simple,
as in the ChaseGame demo. You can also vary the appearance of different
kinds of monsters to make it obvious which subclass you're dealing with;
see the Scribble example code for ways to draw images on the screen.
If you like, you can implement a double buffered drawing surface to make
the animation smoother, as in the Scribble example.
Patterns
For most games, the default game play works fine, but they need to customize
the Player and Monster classes (to change the chase behavior, the combat
behavior, or the UI representation, for example). To do this a client would
first subclass Player or Monster, and subclass Game to create their subclass
instead of the default base class. Some games may require a mixture
of Monsters -- for example, a game might produce 25% snakes, 50% trolls,
and 25% dragons instead of just one subclass.
To do this, use the Factory Method pattern. The Game class should specify
factory methods makePlayer() and makeMonster(). A subclass of Game
will override one or both of these to produce specific subclasses.
The game should still work (with boring, default monsters and player) if
the subclass does not override makePlayer() and makeMonster(). The
subclass of Game is responsible for figuring out the correct subclass of
Player and Monster to create. Normally, the Game base class only
calls makePlayer() once per player lifetime, but calls makeMonster() each
time it decides a new monster needs to appear.
Internals
You may want to consider using a common base class for Monster and Player,
since they share a number of commonalities (they both move on the screen,
they both engage in combat, etc.) This is an internal implementation detail
that shouldn't matter to the client of the adventure package.
The movement of the player can be handled by event listeners, similar
to the Scribble example. The monsters can be handled in one of two
ways, either by a timer event (which causes all of the monsters to move)
or by a set of independent threads, as with the ChaseGame demo.
Test Program
Along with the framework, create a test program that uses the framework.
It should have at least one custom Monster. Make sure that the framework
does not depend on the test program in any way -- you should not
need to modify the framework in order to create a second test program,
for example. Feel free to add additional monster subclasses, change
them during the program's execution, etc. (The framework should support
switching the type of monster that will appear next; for example, you could
do this every 5th time the player moves, or at random.)
Deliverables
Turn in a class diagram, the code, any println output, and a screen shot
of your program. (Under Windows, you can copy screen images to the Clipboard
with Control-PrtScn, then paste to an application like Paintbrush for saving
or printing.)