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.


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 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.


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.


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.)


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.)