My
game framework design is an implementation of the
model-view-controller pattern. It was designed to be flexible for
several reasons. First of all, different types of games need
different internal logic to run. Secondly, it promotes code reuse and
makes future two player games easier and faster to develop.
In Figure 1, I have
given a top-level picture of the classes I have used. Everything
begins with Gui. This is the class that is called when the framework
is to be run either as an applet or as an application. If the applet
is run as an application, then it takes advantage of the various XML
capabilities: saving/restoring games and getting the games from a
"config.xml" file. Gui is a specialization of
java.applet.Applet, so it is kicked off in either case from its
init() method.
One interesting
feature of my design in this diagram is my use of the ModelListener &
ModelEvent classes. I implemented an event handling system similar
to the Java event system. I set up the FrameworkView to implement
the ModelListener interface. Then, the model must be setup in such
a way that ModelListeners can be added & removed from a list kept
by the model. When the model is changed (in this case, when a new
game has been created and the new view is ready to be displayed, then
the FrameworkModel calls each listener's modelChanged() method. As
an added bit of functionality, any object can be passed via the
ModelListener system by wrapping the object in a ModelChangedEvent
and sending it out to the listener. Then, the listener (presumably
knowing what kind of Object it is supposed to receive) can then
unwrap the object and cast it to its true form.
Figure 1
Another
feature of the design that is very flexible and highly reusable is
the GameSettings object. GameSettings is a specialization of
java.util.Hashtable, so it can use any objects as keys & data.
In order make XMLizing my framework a bit easier, only two objects
are XMLized; the GameSettings object and a list of moves.
Effectively, GameSettings is an XMLizable Hashtable.
Figure 2
Here we are given a overview of the FrameworkController and the many
interfaces that are used in implementing a game. The
FrameworkController receives messages from the FrameworkView about
user events. Then, serving the responsibility of a controller, it
responds to those messages in the appropriate way. Most events lead
to making changes in the game's model (the game Layout, which must
implement IgameLayout). In the case of XMLization, the message must
be relayed back to the top-level object (Gui) in order to save the
correct objects. Also, the initFromXML() in FrameworkController is
just a stub, since the FrameworkController will be created from a
XMLized GameSettings object (details to follow). But, the toXML()
method is still used in order to XMLize the history of moves found
from the layout.
Figure
3
In figure 3, I have displayed 3 separate sets of
objects. The first, in the upper-left, an example of what objects
implement the IGame interface. This implementation serves as a
factory that produces the necessary IGame objects that are needed by
the Referee in order to play a game.
The second is
the GameView set of objects. GameView is an abstract class that
extends java.awt.Panel. Originally, the intention of having an
abstract class here instead of an IgameView interfaces was to allow
the Swing functionality a bit later in the development cycle. Even
though the Swing functionality was never fully implemented, the
object still serves the purpose of displaying a game-independent
WinnerBox. Now, each game needs not worry about the panels necessary
to display the winning player. I also used the Null Object pattern
by designing a NullGameView object. This NullGameView would only be
displayed when 1) an error has occurred, and then the NullGameView
will display the exception error , or 2) the application is started
up, which gives the user time to decided which game he/she loads.
The
third set are the Player objects. I have one abstract class Player
that takes care of the basic behavior of assigning names and type of
piece. Every type of player than subclasses the Player class to
write their own player. Computer players implement an additional
IComputerPlayer interface, so that the minimax algorithm can be used
to make its moves. One unique design decision I made here was to
have the Player class implement ActionListener and FocusListener.
Human players take advantage of these interfaces. When it becomes a
player's turn, that player is added as an Action/Focus listner to all
buttons/widgets that inform the framework that a move is going to be
made. This makes intuitive sense because in real life, when it
becomes a new player's turn, that player than starts paying
attention; but when it is not that player's turn, he/she doesn't care
what moves are being made. The FocusListener interfaces is used
specifically in sticks, when a hand-crafted SticksButton is used.
Since Button contains code that depresses the button and such, I
wanted to make sure that the button's surface gets repainted when the
focus is changed.

Figure 4
In
figure 4, I tried to tie up all the lose ends. One things to note
here include that Referee implements Runnable. My reasoning for this
will be seen near the end of this report. The strategies implement
IGameStrategy, not much else to say about that. I have included a
NullGameMove as an implementation of IGameMove. This allows the
referee to be able to "skip" a player; if the Referee gets
a NullMove, than it just switches players and moves on. This handy
feature is utilized by my UndoMove method in FrameworkController.
The layouts for each game C4Layout & SticksLayout each implement
IGameLayout. The Layout classes are the models for the game; they
provide the data & logic of how each game works, and know nothing
about the view. For each game I implemented, it became helpful to
use classes like Cell & Pile to keep things tidy.
Figure 5
I
have included figure 5 in order to describe the initialization
sequence. The top-level object Gui first creates a
FrameworkController object, and then passes that along to the
constructor for FrameworkView. Intuitively it seems that we would
need to have created the FrameworkModel before the View &
Controller, but not in this case. Here I use a static FrameworkModel
that keeps a static list of ModelListeners and a static GameView
attribute. The model keeps track of the current GameView, and when
we want to change that view, all we need to do is call the set()
method on FrameworkModel, and the model takes care of the rest.
Figures 6a & 6b
Figure 7
Figures 6 & 7 both describe the same phenomena, the submission of a move
and the response of the Referee. Figure 6a is a sequence diagram
that represents the submission of a move by a user. As seen from
that diagram, the move that is calculated from the HumanPlayer's
actionPerformed() method is then simply placed in a Hashtable.
The
referee implements Runnable, so it can spin off a new thread. This
thread just checks to see if a move has been placed in the received
Hashtable, and if there is no move, the thread goes to sleep for 100
ms. The reason for having submitMove() work in this unusual manner
allows the GameView time to repaint itself. The GameView panel will
not repaint() until the thread that called repaint is no longer
active. So, by going to deactivating the thread after submitting a
move; I am allowing the AWT paint() methods to occur promptly (and
not just be scheduled for a later time).
The
process of creating the new thread can be seen easily in the Figure 7
state diagram. The upper half of the diagram shows the
initialization, and then the lower half runs in a continuous loop
that repeats the same logic over & over again (including going to
sleep now & then).
Figure
8
Finally,
the last UML model is an object diagram. I used an example game of
sticks to fill out the data for each object at a snapshot in time.
From this figure, it is easy to see that very little data is actually
being kept in each object; but it is also easy to see how the
behavior is encapsulated. Another things to notice here is the
high-coupling in places. It appears that FrameworkController must
know about several objects, but in reality, these objects are just
interfaces so it is not such a major factor. It does, however,
effect the code's level of reusability.
All in all, I am
satisfied with my design. I feel that I generalized the framework to
a maximum degree, at the expense of not having enough time to create
an awesome View for each game. I implemented all the required
features, plus the following 3 bonuses: XML-configurable
framework (in application mode). Runs as an
Applet & as an Application. Uses an
intuitive point & click interfaces with no typing.
Please Note: Save/Restore buttons are inactive when this application is
running as an applet, due to security restrictions on Java Applets.
<APPLET CODE="cs4448.gameFramework.Gui.class" CODEBASE="./" ARCHIVE="hw6.jar,xerces.jar,jdom.jar,collections.jar" WIDTH="600" HEIGHT="400"></APPLET>