Project Implementation
  1. Features Implemented
  2. User Interface
  3. Appearance
  4. Design
    1. UML Diagrams
      1. Object Overview
      2. Universe Class and Collaborators
      3. SpaceObject and ControlledObject
      4. Helper Classes and Interfaces
    2. Patterns Used
  5. Implementation Strategy
    1. Overview
    2. Implementation Sequence
    3. Testing Orbital Dynamics
      1. Precession
      2. Delta-V at Perihelion and Apohelion

Features Implemented

All of the features listed in the proposal for the basic game were implemented. The one concession to modern persistent display technology was the placement (launching) of mines sufficiently far from the ship to allow the mines to be immediately armed. In contrast, in the PDP-12 implementation, the non-persistent monochrome display allowed a yet-to-be-armed mine to be spotted easily even when displayed right on top of the ship.

We also implemented the following features beyond the basic game:

  1. Multiple suns in mutual orbit. By default, the game comes up with a single sun in the middle of the screen. Although this sun is mobile, its simulated mass is on the order of 1012 times that of the ships. Therefore, for all practical purposes, it is immobile. When the "randomize" button is pressed, the game is restarted with a pair of mutually orbiting suns. Ships and missiles are quite difficult to control in the area between the two suns, but orbits around the outside of both suns are quite stable. The object-oriented nature of our implementation made this feature quite easy to implement.
  2. Suns explode when colliding with other suns (or any other object that has at least 10% of the sun’s mass).
  3. Two additional flavors of gravity:
    1. Negative gravity, such that objects repel rather than attracting.
    2. Normal mutually attracting Newtonian gravity, but in a terrestrial gravity well. The pair of suns will orbit each other, but fall down towards the bottom of the screen, where they bounce. The ships are attracted both to the suns and to the bottom of the screen, and also bounce.
    The object-oriented nature of our implementation made these flavors of gravity easy to implement.
  4. Per-ship limited number of mines in flight at a given time. In contrast, the PDP-12 implementation allowed one player to "starve" the other of mines, simply by keeping all 10 in flight from his ship.
  5. "Sticky" collisions. In the PDP-12 implementation, colliding objects would explode and pass through one another. The Java version features more realistic momentum-conserving sticky collisions. Colliding objects stick together, following the same path as they explode.
  6. Conservation of angular momentum when launching missiles and mines. In contrast, the PDP-12 implementation caused mines and missiles to remain pointing in one direction even when launched from a spinning ship.
  7. Simulated speed blur. The overhead of the Java system forces a relatively low display update rate, particularly when running over X-windows, so that the illusion of movement can be lost when objects are moving quickly. Providing simulated speed blur allows the illusion of movement to be maintained despite low display update rates.
  8. Star field in the background. The cosmetic feature was demanded by the three random testers.
  9. Pale green box marking the boundary off which objects bounce. This boundary was needed because different Java implementations seem to allow differing amounts of margin around the edges of panels and frames. Providing an explicit boundary allowed us to allow 50 pixels of "slop" for differing implementations.
User Interface

The blue ship is controlled by the mouse, and the green ship is controlled by the keyboard. The mouse may be used on a grid of nine buttons, arranged as follows:

The keyboard presents the same controls on the numeric keypad (if "Num Lock" is enabled!), using the same pattern so that the numbers map to the functions as follows:

  1. Missile. Launch a missile, but only if this ship does not already have a missile in flight. As soon as a given missile is destroyed, its ship may launch another.
  2. Detonate. Cause the current missile to explode. Does nothing if this ship does not currently have a missile in flight.
  3. Mine. Launch a mine, but only if this ship has fewer than five mines in flight. Just as with missiles, as soon as a mine is destroyed, the ship may launch another in its place.
  4. Left. Start the ship rotating to the left (counter-clockwise).
  5. Stop. Stop the ship’s rotation.
  6. Right. Start the ship rotating to the right (clockwise).
  7. Restart. Restart the game with two ships and a single sun. Use the same type of gravity that was used in the previous game.
  8. Engine. Toggle the engine state, turning it on if it was off and off if it was on.
  9. Randomize. Restart the game with two ships and two suns, randomly selecting gravity from Newtonian (normal free-fall inverse square law), Terrestrial (normal free-fall inverse-square law, but in a strong gravity well), and inverse Newtonian (free-fall inverse square law, but with objects repelling each other rather than attracting each other).
Appearance

The game looks as follows when the full five mines and one missile per ship are in flight.

The sun is in the center of the screen. The tiny white dots are stars. The pale green box is the edge of the universe, off which objects bounce. The small blue and green circles with crosses are mines. The small blue and green circles with flames coming from them are missiles. The large blue and green circles each with the single short line from center to edge are the ships. The lines denote engines, and if the ships’ engines were on, there would be flames emanating from the lines, similar to the flames emanating from the two missiles.

Design

UML Diagrams

Patterns Used

The Universe class is an example of a mediator. All in-flight SpaceObjects’ gravitational and collision interactions are managed by Universe, and SpaceObjects are in general unaware of each other’s position, velocity, state, and existence. There are two exceptions to the lack of awareness of existence: SpaceShips track how many of their SpaceMissiles and SpaceMines are still extant in order to determine whether the player may legally launch another SpaceMissile or SpaceMine. Note that Universe is not a Singleton. As every Star Trek fan knows, limiting your game to a single Universe is just plain shortsighted.

The SpaceGraphics class is an example of a decorator. This class delegates graphics operations to the underlying AWT Graphics object after making the coordinate transformations needed to move from a physics-friendly right-hand-rule coordinate system based on the centers of objects to the increasing-Y-downwards upper-left-corner coordinate system implemented by AWT.

The SpaceObject class serves as a template for the SpaceSun, SpaceShip, SpaceMissile, and SpaceMine classes.

The SpaceObjectRegistry class serves as an abstract factory. New SpaceSuns, SpaceShips, SpaceMissiles, and SpaceMines may be created by sending the SpaceObjectRegistry a message containing the string "sun", "ship", "missile", and "mine", respectively. The SpaceObjectRegistry class is also a singleton: its constructor is private, and all of its methods and instance variables are declared static.

The SpaceObjectListIterator serves as an iterator. This object reduces the number of explicit cast operations required, and supports "all pairs only once" scanning by allowing a iterator to start after a particular object. This simplifies scanning SpaceObject lists when computing gravity or checking for collisions.

Implementation Strategy

Overview

We used a "spiral" implementation methodology. Paul implemented from the display in towards the model, while Venu implemented from the keyboard and mouse in towards the model. We integrated our two components once per week. This approach allows incremental testing with very low scaffolding-creation overhead. Each component was tested as it was created; using previously constructed and tested components as test scaffolding.

Venu used the title bars of the input components to display text messages, thereby verifying that input components were providing the correct response to user input. Paul used hard-coded placement of SpaceObjects with Java statements to verify that the display and the model components were working correctly.

Between these functional tests were interspersed the unplanned, but surprisingly useful, random testing efforts of Melissa, Sarah, and Aaron, Paul’s three children.

Implementation Sequence

  1. SpaceGraphics and SpaceGraphicsFlipCenter. These are closest to the display, and formed the basis for further testing of the model.
  2. RemoteControl version 1. These are closest to user input. Unit testing was accomplished by modifying the frame titles to verify that mouse clicks and keystrokes were indeed being correctly responded to.
  3. Universe, MetricSpace, MetricSpaceEuclideanBounce, Gravity, GravityNewtonian, SpaceObject, SpaceSun, SpaceShip, ControlledObject. These were integrated and tested in a large group due to Paul’s being out of town. They were coded at airports and on board airplanes, and tested upon return. Various tests were run by having the initialization code set up the objects in a known state, for example, one of the ships with its engine on while rotating left, and the other with its engine on without rotating.
  4. RemoteControl version 2. This version used ControlledObject, allowing direct control of the ships. This made it possible to test orbital dynamics.
  5. SpaceMine, SpaceMissile, SpaceObjectRegistry, GravityInverseNewtonian, GravityTerrestrial. The mines and missiles were again placed by the initialization code, since RemoteControl version 2 could not control them. The type of gravity was also selected by the initialization code.
  6. RemoteControl version 3. This version allowed mines and missiles to be launched.
  7. SpaceBackground, SpaceBackgroundStars. This was not planned, but added due to overwhelming demand by Paul’s wife and children. J
  8. RemoteControl version 3. This version allowed the game to be restarted and allowed random selection of types of gravity.
Testing Orbital Dynamics

We did specific tests for precession and for delta-V at perihelion and apohelion. The precession and delta-V tests are covered in the following subsections.

Precession

In theory, orbits should be perfect ellipses, parabolas, and hyperbolas. However, calculation errors cause the simulated orbits to deviate from their theoretical forms. There are two major sources of error: (1) roundoff error and (2) integration error.

Although roundoff error was the major contribution to error in the PDP-12 implementation, it is negligible in the Java implementation due to Java’s 64-bit IEEE floating point arithmetic.

However, integration error is significant, especially on highly elliptical orbits. The following diagram helps illustrate integration error:

This diagram shows a blue object in a clockwise elliptical orbit around the sun. We simulated motion using Eulerian integration, which means that we compute the force at a time t1, compute the resulting acceleration, change in velocity, and new position at time t2. However, the force will be changing continuously as the object moves from t1 to t2, and will be changing especially quickly when the object is passing close to the sun in an elliptical orbit. The diagram shows the force of gravity pulling the object upwards and to the right at t1. Eulerian integration uses this same force vector for the entire path from t1 to t2, with about 700 of error in direction of the force at point t2. This error results in precession. Highly elliptical orbits precess about 2 degrees per minute.

Delta-V at Perihelion and Apohelion

If an object is given an impulse (short burst of acceleration) at perihelion, this will cause the apohelion to move, but will not affect the perihelion. This is shown in the following diagram: an impulse in the direction of motion at perihelion causes the object to move from the inner orbit to the outer orbit. (A subsequent identical impulse at perihelion against the direction of motion would cause the object to revert back to the inner orbit.

Similarly, an impulse at apohelion will affect the perihelion, but not the apohelion.

Tests on our SpaceWar game showed that our simulation of gravity closely obeyed this law of motion.