Our design is divided into six packages. The base package
defines the interfaces used by components in a GizmoBall game.
The filesystem and geometry packages provide library methods for
dealing with the filesystem and geometry calculations.
The gizmos and envmods packages contain implementations
of specific game elements. The ui package contains the main
method of our GizmoBall game and all user interface classes, including
our “text mode”.
base |
common classes |
filesystem |
filesystem utilities |
ui |
user interface classes |
gizmos |
specific gizmos |
envmods |
specific environment modifiers |
geometry |
geometry utilities |
All objects that may appear on a GizmoBall board are inheited
from the GameItem class. Each type of gizmo has its own class,
and inherits from the abstract Gizmo class. The GizmoBall board
is represented by the Level class in both building and run mode,
but an additional class, GizmoGame, is responsible for updating
the state of a GizmoBall game in progress. The physical parameters
of the board such as gravity and friction are encapsulated in the
Environment class; the environment is implemented as a stack of
modifiers, which allow us to have custom environmental effects
such as gravity waves.
The Gizmo class itself contains a considerable amount of functionality.
Each gizmo maintains a list of its targets, can draw itself on an
arbitrary Graphics2D, and
responds to collisions with balls.
The user interface is centered around the GizmoWindow class, which
contains the main method. In both building and run mode, the gizmoball
board is drawn by the GizmoBoard class. A number of dialog box
classes exist to edit properties of gizmos, connections, etc.
We also have classes to add music and sprite-based themes to the
user interface.
We chose to use the GameItem class as a common superclass to
provide a simple common interface for game elements. In particular,
GameItems are all capable of drawing themselves dependent only
upon their internal state, updating their internal state for a
specified period of time, resetting their internal state, and
providing a list of gizmoball board sectors they are associated with.
The Gizmo abstract class was included for two reasons: a common
set of methods for gizmos, and utilities to handle common gizmo tasks.
The Gizmo class is sufficiently general that all gizmo functionality
excluding creation and saving to XML uses the methods defined in Gizmo.
Gizmo also implements functionality common to all gizmos, such as
triggering and responding to key events. This design takes advantage
of the template design pattern, calling protected methods that are
overridden by subclasses.
The GizmoGame class provides a single interface to
the state-dependent behavior of GameItems. GizmoGame provides
single methods to draw a game, reset a game, and update a game
for a specified time.
The user interface uses the model-view-controller design pattern.
The gizmos contained in a GizmoGame or Level constitute the model,
the GizmoBoard acts as two views, building and run modes, and the
rest of the ui package acts as a controller. The MVC pattern, combined
with the decoupling of draw and update methods, allows the view to
be completely replaced. While gizmos do determine how they are to be drawn,
their draw methods are only called by the UI code and work on an arbitrary
surface; thus it is possible to run full simulations without the user interface.
This is demonstrated by our “stress test” which runs the simulation for an
extended period of time to make sure that the balls never escape the board,
and our special UI class TextMode which provides an ASCII art version
of GizmoBall.
We also have a minimally-invasive theming system, built around the class Theme, which implements the Singleton design pattern. We have written several themes, which are a combination of a custom XML file (which we have written a schema for) and a directory of images and sounds. The theme specifies images for as many types of gizmos as it likes, and each gizmo checks the currently loaded theme as it draws itself; however, if a theme does not contain an image for a given gizmo it simply falls back to the unthemed picture. This allows us to vastly modify the appearance of the game without making any code changes
The flexibility of our design is underscored by the variety of uses we have been able to put it to. For example, we created a board that simlulates the “labyrinth” game, where you roll a marble around a wooden maze by tilting it and try to avoid holes. By creating a zero-gravity level with gravity waves connected to keypresses to simulate tilts and absorbers to simulate holes, we were able to create a fun and challenging version of labyrinth—inside GizmoBall!
Our testing policy was based on JUnit-based unit and stress testing, massive
amounts of unautomated UI testing, and careful analysis of each other’s code.
We have a variety of JUnit unit tests covering the important properties
of all of the base and gizmo classes, which we ran nearly continuous. We also
have a smaller number of “intensive” stress tests in JUnit which run levels
for a large period of time, looking for erroneous conditions. We also have
standard checkRep methods for our most important classes, which are checked
judiciously. We developed an informal “interaction test suite” of important
actions that would be done and made sure to thoroughly test our interface after
any major change. Finally, we made sure that every module of the system
had two team members who focused on them and kept our relationship as teammates
comfortable enough that we could analyze each submitted changelog in depth
and make appropriate fixes without hurting each other’s egos.
Overall, we are very happy with the state of our project. We implemented roughly everything in the specification, with only a very small number of outstanding bugs (mostly related to dealing with board files that contain overlapping gizmos). We had a high level of modularity, as seen by our alternative interface such as text mode. We have a very attractive yet simple theming system, and a variety of fun boards to play.
Our collaboration was mostly based on communication. We considered splitting the work into four separate parts with well-defined solid edges. However, we ended up moving towards a more agile form of development, where we were each responsible for at least two major parts of the project and each part had two teammates working on it. This enabled us to quickly catch bugs and potential problems in each other’s coding. Our use of a Subversion repository with email- and zephyr- based notifications was essential for keeping us up to date with each other, as was our zephyr class which was in practically constant use for a month. Rather than have formal weekly meetings, we had a near-continuous well-logged conversation about our project. We found that this informal collaboration method vastly increased our productivity.
In retrospect, there are some things that we should have done earlier, especially retooling the project to work under Java WebStart. That change ended up making our two Windows-using team members unable to compile and run the code for around eight hours on one of the final days of the project. Fortunately, the modularity of our project enabled them to still create levels and themes during that time, making it not a waste at all. In addition, had we started using JARs earlier, we might have managed to allow themes to be loaded out of a ZIP file instead of from a combination of XML and a directory of other files.
Most of the important content of our preliminary design document survived through to the present without seriously changing. We kept our specification flexible and made sure to all synchronize with our Subversion repository very often; however, overall our design did not change much. We did change a few of our UI ideas, like moving away from context menus. In addition, we dropped a few “extra features” we had put into our design document (such as user-customizable polygonal gizmos, a complete score system, and multi-level linking), although we had known all along that not completing these optional features were likely. On the other hand, we added a few optional features, such as our fleshed-out theme system, breakaway bumpers, and gravitational shock waves. We stayed roughly on our timetable, having planned around major academic conflicts.