|
Core Classes:
|
| GameApplet: |
Represents the View in our Model/View Design pattern. Since all of our
games are essentially Guis, we decided to colocate the View/Controller
so that this class drew the Gui as well as controlled the game. It is
structured as an applet in that it has no constructor but uses the
function init() to initialize. However, it does have a main function
so that it can be run as an application as well as an applet. This
functionality is provided by the GameAppletFrame class. All two-player
board games will subclass this class.
This class also provides the basic look and feel of a two-player
game. It has a Game menu with a default of one Options item. See the
OptionsDialog class descriptions for further details on what this
Dialog provides. This class also has the generic GameModel and
GameGrid and two GamePlayer objects ready and initialized. It also has
a message bar at the bottom to allow for output of informational
messages.
There are two important abstract methods that a specific game must
implement. They are update() and gameOver(). The update() functions
needs to implemented because our Model/View classes make use of the
Java Observer/Observable classes to facilitate the Model/View
design. This method is called whenever the Model changes so that this
class can redraw the View to reflect the changes.
|
| GameAppletFrame: |
Allows a GameApplet to be framed inside a JFrame to be used as an
application. In the main method of the applet/application, we make a
new frame of this kind. The one catch is that if the program is
started by the Java interpreter and not the applet viewer, and it
calls getAppletContext, it gets a null pointer because it has not been
launched inside a browser. To deal with this, we implement these
function, even though we implement them to do nothing. For example,
the showStatus(message) method displays no message but it at leastit
doesn't crash the program. It turns out that we only needed to
implement two interfaces: AppletStub and AppletContext. This class is
generic enough to not be subclassed.
|
| GameModel: |
Represents the Model in our Model/View design patter. For our board
games, this class essentially consisted of the GameBoard class which
models a typical game board. This class does not need to be subclassed
by any games
|
| GameBoard: |
Represents a typical game board so should be subclassed by any
specific two-player board game. Essentially, the main constituent of
this class is a single array of Strings that correspond to individual
boxes on a game board.
|
| GameGrid: |
This is the JPanel used to implement the View of each of our
games. Each game uses JButton's as the individual components
representing game pieces. In a sense, the GameGrid was used as a
generic Button Panel. This panel allows for the animation of
components as they can be moved across the grid. This structure is
also perfectly capable of being used as a plain old ordinary grid (it
is used in this fashion in both Chomp and TicTacToe). The animation
works with any Component, however clicking detection only works on
panels that extend AbstractButton.
Features include:
- Automatic detection and reporting of grid clicks for AbstractButtons in this grid.
- Buffered mass movements of components, that is, one can specify as
many movements as one wants and they will all happen
simultaneously.
- You can fly components onto the screen from outside the space of the
grid, as though they had actually come from that location.
- Same, but vice versa: you can fly existing components off the grid.
- You can fly components past the grid... from non-existing places to
non-existing places, whatever you please.
- A RealFunction object can be passed in to affect the style of
movements of the components as they fly about.
This class was written by Thomas Finley.
|
| GamePlayer: |
Represents a generic player for games. This class was made extensible
to allow for Human and Machine player implementations. When we sat
down and designed this class, we were looking to achieve a GamePlayer
that was more than just a placeholder for the name/icon of a
player. We wanted to write the classes to model the real life
situation in which the players control the flow of the game by
deciding when turns have been taken and whose turn it is. We found
this extremely difficult to do at first as this lead to the GamePlayer
class needing explicit knowlegde of each individual GUI. We knew this
was not a desireable result and it lead us to believe that the control
of the game should just be implemented in the View/GUI. But, we then
looked to Threads, and this gave us exactly the result that we
wanted. The GamePlayer class no longer needed specific knowledge of
the GUI. Each player first waits until it is his turn while the other
player or players makes their moves. When it is a player's turn, the
GamePlayer Thread waits until a cell/position has been selected on the
GameGrid. The View then informs the GamePlayer that a move has been
made and if it is a valid move the GamePlayer Thread informs the next
GamePlayer Thread to take its turn. If a valid move has not been made,
the current GamePlayer Thread continues to wait until a valid move has
been made. These classes worked out beautifully in taking the control
of the flow of the game outside of the view and placing it where it
belongs - with the players.
The flow of the game is controlled in the run() functions of each of the GamePlayer threads:
public synchronized void run()
{
while(!myTimeToStop)
{
// don't continue until it is your turn
while (turn != this && !myTimeToStop)
{
try
{
// wait until it is your turn
wait();
// wake up from turn method
}
catch (InterruptedException ex)
{
return;
}
}
if (myTimeToStop)
{
return;
}
// inform the view that it is now your turn
myView.displayMessage(getPlayerName() + "'s turn");
// continue to make moves until a valid move is made
while (true)
{
// make your move - this function should be overridden in the
// HumanPlayer and MachinePlayer subclasses
int move = makeMove();
if (myTimeToStop)
{
return;
}
if (myView.makeMove(myMove))
{
break;
}
}
turn = null;
// tell the next player that it is now his/her turn
next.turn();
}
|
| HumanPlayer: |
Subclass of GamePlayer which simply overloads the makeMove() function
to allow a human to select a cell on the GameGrid as their move. The
function looks as follows:
public synchronized int makeMove()
{
try
{
wait();
}
catch (InterruptedException e) {}
return myMove;
}
As you can see, the HumanPlayer Thread simply waits. The idea is that
when the user clicks on a cell of the GameGrid to select a move, the
view calls the selectCell function of the HumanPlayer:
/**
* Sets the move of this player and executes it
*/
public synchronized void selectCell(int x)
{
myMove = x;
notifyAll();
}
This function sets the move of the HumanPlayer to the cell that was
selected on the GameGrid and then notifyAll() is called. This function
awakens all threads that are waiting. Specifically, the HumanPlayer
Thread is awoken from its waiting and returns its newly selected
move.
|
| MachinePlayer: |
Subclass of GamePlayer which simply overloads the makeMove() function to allow an artificial intelligence(a machine - specfically, the computer) to select a cell on the GameGrid as their move.
|
| OptionsDialog: |
This is dialog that pops up when user clicks on Game -> Options. It is
a modal dialog which means that the user must press ok or cancel
before he/she can resume with the game. All of the two-player games
use this dialog to allow the players to make choices in terms of who
goes first, which player gets which game piece, and whether it will be
a one or two player game. A one player game simply sets the other
player to use a machine player. This class easily allows for removal
of any of the default options by having a removePanel() method, which
was used in Chomp, for example. For each individual option, we made
use of the OptionPanel class, which is described below.
|
| OptionPanel: |
This class is that provides a panel with radio buttons inside a titled
border for the OptionsDialog class. Each radio button is a choice the
user can pick.
|
|