Handout F4

Quick links:

Contents:

Note: Some 6.170 students have acquired Repetitive Strain Injuries (RSI) over the course of the final project in the past. Don't let it happen to you. It hurts. Please read the MIT web site about RSI before embarking on the final project.

Amendment

The amendment has been released. It can be found here.

This year's amendment will ask you to implement a variable time delay on the actions of each gizmo.

Introduction

The goal of the project is to design, document, build, and test a program that plays Gizmoball. Gizmoball is a three dimensional version of pinball, an arcade game in which the object is to keep a ball moving around in the game, without falling off the bottom of the playing area. The player controls a set of flippers that can bat at the ball as it falls.

The advantage of Gizmoball over a traditional pinball machine is that Gizmoball allows users to construct their own machine layout by placing gizmos (such as bumpers, flippers, and absorbers) on the playing field. These machine layouts may also form complicated "Rube Goldberg" contraptions that are intended to be watched rather than played. (If you don't know what a Rube Goldberg machine is, see http://www.anl.gov/Careers/Education/rube/ or http://www.rube-goldberg.com/). As an optional extension (after you have designed, documented, implemented, and tested all required functionality), you may create new varieties of gizmos that can be placed on a playing field.

Gizmoball Overview

Because this project is in part a design exercise, the assignment specifies what the user should be able to do and leaves it up to you to figure out what modules and interfaces are appropriate. This section gives an overview of Gizmoball. A more detailed specification is given in Appendix 1. To enable automated testing, your implementation must support an XML file format (defined in Appendix 2), in addition to the loosely-specified graphical user interface.

Gizmoball has a graphical user interface with two modes, building mode and running mode.

Here is a screenshot of one implementation of Gizmoball. Your implementation will look different (depending on your choice of user interface), and your ball motion may not exactly match the given animation.

Gizmoball example top
Gizmoball example left Gizmoball example animation
Gizmoball example bottom

This example illustrates the most important features of Gizmoball.

Awards

Each team may enter its Gizmoball implementation into a class contest for one or more of the following awards:

Best design:
Awarded for the project with the best abstraction, modularity, extensibility, simplicity, etc. The quality of the final report is also considered.
Best Gizmoball game/usability:
Awarded for the project with the best game-play and best user interface. Part of your submission for this prize should be an input file that sets up the playing area; the prize is for the playable game itself, not for the construction kit.
Most artistic:
Awarded for the project that is the most beautiful or fascinating to watch. Part of your submission for this prize should be an input file that sets up the playing area. When run with this input file, the ball or balls should bounce around forever without the user needing to press any keys.

Whether your program implements only the basic required functionality (extra gizmos etc.) will not be considered when making the design award. However extra functionality that improves game-play or "Rube Goldberg" artistry will be an asset in competing for the other two awards.

Judging will be done initially by the TAs and final judgments will be made by the lecturers. Winners will be announced at the last class on May 16.

Grading, Deliverables and Schedule

You'll do your project in phases, with the following milestones:

Phase Deliverables Due date
Preliminary Design Preliminary design document 4/18/07
Preliminary Release Source code, specifications, unit tests 5/1/07
Final Release Final design document, source code, specifications, unit tests, user manual, webstart packaging 5/14/07

In addition, there will be weekly meetings with your TA between April 9 and May 7, with a progress document due at each.

Each team will receive a single grade for the final project.

The Final Project Grading, Deliverables, and Schedule document has more information about these stages, how they are graded, and what is required at each. You should be sure to read through this document now, so that you are not caught unprepared by what is expected.

The following additional requirements apply to the Gizmoball project:

Required Preliminary Release Functionality

At the preliminary release deadline, we will ask you to demonstrate some specific Gizmoball functionality:

Your animation in run mode should be smooth and adequate to demonstrate the features required above.

Your Gizmoball submission should be runnable as a stand-alone application packaged with the JAWS tool

Resources

See the Final Project Tools document for information on tools that may help make your work faster, more efficent, and more enjoyable.

Provided Code

You will use the java.awt and javax.swing packages to construct your graphical user interface (GUI), to implement the three dimensional graphics package, you will be using the Java OpenGL (JOGL) wrapper libaries. A Cookbook of how to get started with these libraries is provided here for the physics library, and here for the opengl library.

We have provided you with a demonstration program in Example.java that demonstrates how to get your program to listen to user events, such as clicking on a toolbar button, pressing a key or dragging the mouse. All members of your group should be able to compile and execute this demo GUI.

We have also provided you with a library of physics routines (see Appendix 3) for representing shapes, and calculating the dynamics of elastic collisions in three dimensions. You are welcome to use this code as is, or modify it in any way that you like.

Provided Demo

We've also provided you with a 3D graphics demo to display a bouncing ball in opengl

Bouncing Ball

The source for this demo can be found in the gizmodemo jar file, located here, and should help with basic opengl and physics. For help getting opengl working with the demo, be sure to read the setup instructions in the OpenGL Cookbook.

Hints

General

Design
A careful design will save you a lot of time in the long run. It's well known that a small mistake made early in a project can become a big problem if it's not caught until much later. The preliminary design is a major part of the project (more so than its proportion of the grade might indicate). Do it very carefully, trying to anticipate problems that may arise. Then the rest of your project will be more straightforward and more fun.
Prototype
One of the largest challenges for this kind of design problem is figuring out where the "gotchas" are. If you are having difficulty imagining how to structure one part of the design it sometimes helps to build a small prototype.
Validate early and often
Validation shouldn't be an afterthought! You may choose a design because its implementation will be easier to test. Make sure you validate your code as you implement.
Document early and often
Incomplete documentation is better than no documentation at all. If a potential problem or subtlety occurs to you, but you don't have time (or are unable) to formulate it properly, then just add a few sentences in your document describing the issue. Later, if you have time, you can go back and fix it.
Don't over-document
Don't include any redundant material. For example, there's no need to explain the difference between black-box and glass-box testing. Just indicate which of your test cases fall in each category. Similarly, being rigorous is not the same as belaboring the obvious. You can assume that your TA knows what a set or a stack is. There's no need to explain something from scratch when you can use standard terms and notions.
Have fun being on a team
Enjoy being part of a team. Run new ideas past your partners, and discuss problems with them. Read and discuss each others code. A good way to find a bug is to ask someone else to look at your code. Start early!
Communicate effectively
Each meeting you hold with your team members (or your TA) should have: The roles should rotate among the group members; in 6.170, no one individual should perform any of the roles disproportionately often.
Prioritize
We had fun putting together this project. Our goal was to provide you with a project that is both very challenging and offers many opportunities for you to be creative. We encourage you to experiment. Make your implementation of Gizmoball as beautiful to watch, and as fun to play as possible. That said, make sure you get the basic functionality working before you add new features, really cool Gizmos, or an elaborate GUI. The best way to approach extensions to the project is to make your initial design flexible and extensible.

Coding

You should acquire background knowledge about Swing before attempting to code your GUI. You can see Sun's Swing tutorial (particularly the quick tour).

Do not try to use the realtime clock in order to determine timing information. Instead, arrange to receive a timer event every 1/framesPerSecond and proceed to do the simulation and screen updates in response to this event. If you get behind and time slows down, so be it. A simple way to set this up is do use the javax.swing.Timer class, as in the example GUI. Using this approach will simplify the implementation of your code and will also avoid the need to deal with synchronization issues in a multi-threaded program.

In order to respond to mouse and keyboard actions from the user you will want to create and install MouseListener, MouseMotionListener, and KeyListener all of which can be found in the java.awt.event package. Information about Java keycodes can be found in the documentation for java.awt.event.KeyEvent.

Keypress

The specifications for handling keyboard input in Gizmoball require that an object connected to a key is triggered when that key is pressed or released. This provides behavior similar to that of a real pinball game: hitting the button causes the flipper to swing upward and releasing the button causes the flipper to return to its rest position.

Keyboard events

The Java specifications for java.awt.event.KeyEvent describe three types of key events, KEY_PRESSED, KEY_TYPED, and KEY_RELEASED. The documentation suggests that KEY_PRESSED events occur when a key is actually depressed by the user and KEY_RELEASED events occur when the key is released. It would therefore seem reasonable to trigger when receiving a KEY_PRESSED or KEY_RELEASED event for a given key bound to a gizmo.

Unfortunately, most Java runtime environments fire multiple KEY_PRESSED and in some cases multiple KEY_RELEASED events when the user has only pressed the key once. Additionally, in some environments you may never receive the KEY_RELEASED events for an upstroke. This is because the behavior of KEY_PRESSED and KEY_RELEASED is system dependent. The behavior occurs through an interaction with the operating system's handling of key repeats that occur when you hold down a key for a period of time.

On Windows

On Windows, Java will produce multiple KEY_PRESSED events as the key is held down and only one KEY_RELEASED when the key is actually released. For example, holding down the 'A' key will generate these events:

PRESSED 'A'
PRESSED 'A'
...
RELEASED 'A'

On Unix

On Unix, multiple pairs of KEY_PRESSED and KEY_RELEASED are received as the key is held down:
PRESSED 'A'
RELEASED 'A'
PRESSED 'A'
RELEASED 'A'
...
PRESSED 'A'
RELEASED 'A'

Test Program

If you want to explore the behavior of your in your environment, you can use the KeypressTest class provided by the staff. The application will dump all keyboard events to the console for inspection.

The source code is available at KeypressTest.java

Solutions

You should feel free to handle this nuance of the Java API as you see fit. One easy solution is to shut off the operating system's automatic key press repeat mechanism and thereby cause the KEY_PRESSED and KEY_RELEASED events to more closely correspond to the actual actions of the user.

Asking the end user to perform settings such as these is acceptable, but should be included in your Gizmoball documentation.

An alternative solution is to take advantage of a special key listener decorator provided by the staff. The class is available in compiled form in the gb-lib.jar file as staffui.MagicKeyListener. Refer to the documentation for MagicKeyListener or use the provided source code as your own starting point.

XML Schema validation

Assuming you are using the XML DOM (Document class), the following code will help you set up XML Schema validation. First, define the following string constants:

    // Constants used for JAXP 1.2
    protected static final String JAXP_SCHEMA_LANGUAGE =
        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    protected static final String W3C_XML_SCHEMA =
        "http://www.w3.org/2001/XMLSchema";
    protected static final String JAXP_SCHEMA_SOURCE =
        "http://java.sun.com/xml/jaxp/properties/schemaSource";

Then, when you have created a DocumentBuilderFactory called dbf, set it up with the following calls (gbSchema must be an InputSource pointing to the Gizmoball schema file or URL):

        dbf.setNamespaceAware(true);
        dbf.setValidating(true);
        dbf.setIgnoringElementContentWhitespace(true);
        dbf.setIgnoringComments(true);
        dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
        dbf.setAttribute(JAXP_SCHEMA_SOURCE, xsdSchema);

Appendix 1: Detailed Requirements

General

Your Gizmoball submission should be packaged with the JAWS tool, and be playable as a stand-alone application.

Your implementation must support two modes of execution: building and running. In building mode, the user can add gizmos to the playing area and can modify the existing ones. In running mode, a ball moves around the playing area and interacts with the gizmos.

Playing Area

Your Gizmoball game will be required to support three dimensional graphics and limited three dimensional gameplay. Specifically, this means that your physics engine will be required to handle physics in any fixed z coordinate, your playing field will be required to draw all objects in three dimensions, and your build mode will be required to allow the creation and editing of gizmos in a three dimensional grid-space.

Specifically, you need to be able to load and build boards containing balls and gizmos with any Z coordinate in the appropriate range. However, you will not be required to support balls with a Z velocity other than 0. (You may, if you wish.)

To describe dimensions in the playing area, we define L be the basic distance unit, equal to the edge length of a square bumper.

In order to clarify the description of this three dimensional gamespace, the following termonology will be used:

Assuming that you are looking at the 170 demo on the computer screen:

Corresponding to standard usage in the graphics community, the origin is in the upper-left-front corner with coordinates increasing to the right-bottom-back. During the course of the game, you are allowed to change the view of the game. However, this initial standardization is important because it assures everyone is using a right handed coordinate system, and also ensures that maps will look the same when initially loaded on any program.

A z value for gizmos on purely two dimensional map might be z = 9, with the z value for the ball being z = 9.75, like example.xml. This corresponds to the back, which is the fartest plane away from the computer screen. However, the physics spec indicates that your program must behave identically for any z. For example, if you subtracted 7 from the z value for each ball and gizmo in example.xml, the playing area should look smilar to and act identically as before, except that everything would be shifted forwards by 7 L.

The playing area must be at least 20 L wide (x) by 20 L high (y) by 10 L tall (z). That is, 400 square bumpers could be placed on the playing area in the XY Plane without overlapping, and there could be three such layers stacked on top of each other in the Z dimension. The upper-left-front corner is (0,0,0) and the lower-right-back corner is (20,20,10). When we say a gizmo is at a particular location, that means that the gizmo's origin is at that location. The origin of each of the standard gizmos is the upper-left-front corner of its bounding box, so the location furthest from the origin at which a gizmo may be placed is (19,19,9) on a 20L x 20L x 10L board. The origin of a ball is at its center.

During building mode, Gizmos should "snap" to a 1 L by 1 L by 1 L grid. That is, a user may only place gizmos at locations (0,0,0), (0,1,1), (0,2,0), and so on. In this building mode you will probably find it to be most straightforward to snap to two of these dimensions at a time while keeping one constant, depending on a set perspective.

During running mode the animation grid may be no coarser than 0.05 L by 0.05 L by 0.05 L. Suppose that the ball is at (1,1,.5) and is moving in the (1,0,0) direction -- that is, left to right -- at a rate of .05L per frame redraw. Then the ball should be displayed at least in positions (1,1,.5), (1.05,1,.5), (1.10,1,.5), and can be displayed at more positions if you wish the animation to be smoother. Rotating flippers can be animated somewhat more coarsely; see the precise description of flippers below. If the ball is moving faster than the animation grid size per frame redraw, it need not be redrawn in each animation grid position.

Building Mode

In building mode the user can:

Running Mode

In running mode, the user can:

In running mode, Gizmoball should:

Standard Gizmos

There are seven standard gizmos that must be supported: bumpers (square, circular, and triangular), flippers (left and right), absorbers, and outer walls.

A coefficient of reflection of 1.0 means that the energy of the ball leaving the bumper is equal to the energy with which it hit the bumper, but the ball is traveling in a different direction. As an extension, you may support bumpers with coefficients above or below 1.0 as well.

All standard gizmos have a depth of 1L, making them prisms. As such, a ball with no velocity in the z direction whose center is between integer values in Z will interact with these gizmos in a two dimensional manner.

Square Bumper

A square shape with edge length 1L and a depth of 1L
Trigger: generated whenever the ball hits it
Action: none required
Coefficient of reflection: 1.0

Circular Bumper

A circular shape with diameter 1L and a depth of 1L
Trigger: generated whenever the ball hits it
Action: none required
Coefficient of reflection: 1.0

Triangular Bumper

A right-triangular shape with sides of length 1L, a hypotenuse of length Sqrt(2)L, and a depth of 1L
Trigger: generated whenever the ball hits it
Action: none required
Coefficient of reflection: 1.0

Flipper

A generally rectangular rotating shape with bounding box of size 2Lx2L , and a depth of 1L
Trigger: generated whenever the ball hits it
Action: rotates 90 degrees (see below)
Coefficient of reflection: 0.95 (but see below)

Flippers are required to come in two different varieties, left flippers and right flippers. A left flipper begins its rotation in a counter-clockwise and a right flipper begins its rotation in a clockwise direction.

During run mode, a flipper should never extend outside its bounding box. In edit mode the flipper should not be permitted to be placed in any way which would cause the flipper to extend outside of its bounding box during run mode, or would cause the flipper's bounding box to overlap with (the bounding box of) another gizmo.

The below pictures show flipper placements for various initial rotations. In run-mode, when a flipper is first triggered, it sweeps 90° in the direction indicated by the arrows. If triggered again, the flipper sweeps back 90° to the initial position.

In the pictures, the shape and design of the flippers are for illustrative purpose only -- your final design may differ.

Flippers
Flipper initial placements and initial directions of rotation.

As with the three standard bumpers, a flipper generates a trigger whenever the ball hits it.

When a flipper's action is triggered, the flipper rotates at a constant angular velocity of 1080 degrees per second to a position 90 degrees away from its starting position. When its action is triggered a second time, the flipper rotates back to its original position at an angular velocity of 1080 degrees per second.

If its action is triggered while the flipper is rotating, the exact behavior is at your discretion. Here are some suggestions, but you are not limited to these options:

  1. Ignore triggers while the flipper is in motion. This behavior may be undesirable for the user because a single press and release of a key might not cause the flipper to return to its original position.
  2. Wait until the flipper finishes rotating (and responding to any previously-received triggers) before responding to the action. This behavior may be undesirable for the user because several quick keypresses in a row could cause the flipper to flip repeatedly for a long period of time.
  3. Queue at most one trigger during the initial forward motion and have no queue during the return motion. With this model, a keypress which generated two triggers would cause the flipper to flip and return, but quick repeated keypresses would not tie up the flipper for a long time.
  4. Respond to all triggers immediately. If a flipper is in a forward motion and is triggered, it will immediately switch to a backward motion. In this way, flippers with a key up and down as triggers will behave most like flippers in a real-world pinball game.

The standard coefficient of reflection for a flipper is 0.95. However, when computing the behavior of a ball bouncing off the flipper, you must account for the linear velocity of the part of the flipper that contacts the ball; therefore the ball may leave the flipper with a higher energy than it had when it reached it.

Absorber

A rectangle with integral-length sides and a default depth of 1L
Trigger: generated whenever the ball hits it
Action: shoots out a stored ball (see below)
Coefficient of reflection: not applicable; the ball is captured

When a ball hits an absorber, the absorber stops the ball and holds it (unmoving) in the bottom-right-back corner of the absorber. The ball's center is .25L from the bottom of the absorber, .25L from the right side of the absorber, and .25L from the back side of the absorber.

If the absorber is holding a ball, then the action of an absorber, when it is triggered, is to shoot the ball in the direction of the 'top' of the playing area. By default, the initial velocity of the ball should be 50L/sec in the negative Y direction. (With the default gravity and the default values for friction, the value of 50L/sec gives the ball enough energy to lightly collide with the top wall, if the bottom of the absorber is at y=20L.) If the absorber is not holding the ball, or if the previously ejected ball has not yet left the absorber, then the absorber takes no action when it receives a trigger signal.

Absorbers cannot be rotated.

Outer Walls

Impermeable barriers surrounding the playfield.
Trigger: generated whenever the ball hits it
Action: none required
Coefficient of reflection: 1.0

A Gizmoball game supports exactly one set of outer walls. The user cannot move, delete, or rotate the outer walls. The outer walls lie just outside the playing area:

It is not required that the user be able to use the GUI to connect the trigger produced by the outer walls with any of the other gizmos. However, the standard file format does support this kind of connection.

Appendix 2: The Gizmoball File Format

Informal Description

Game files are stored in an text file format known as XML which stands for eXtensible Markup Language. XML has a well-defined, treelike structure; thus, it is straightforward to check if an XML document is well-formed (as compared to an arbitary tab- or space- delimited file format, which might be easier for people to read). Java 5 has built-in XML support, called JAXP (tutorial). Also see the w3schools tutorial on XML.

Not every XML file is a valid Gizmoball level file. An XML Schema is a file written in XML that defines the desired format for other XML files.

We provide you with an XML Schema gb_level.xsd that defines the XML format for a level of Gizmoball. Any XML file that validates against gb_level.xsd should be able to be loaded by your Gizmoball application. Conversely, any XML file that does not validate against the schema should be rejected by your application, and an appropriate error message should be displayed to the user.

We have made the schema eXtensible, so if you decide to add special features to your own Gizmoball application, you can extend our file format to save this additional information. Because of this flexibility, game files written by your application should be able to be read by any other team's application, even if the other applications do not have, or do not know about, the special features that your application has.

The following is an example of a very simple Gizmoball level file:


<board>
<ball name="Ball" x="1.8" y="4.5" z="9.5" xVelocity="-3.4" yVelocity="-2.3" zVelocity="0.0" /> <gizmos> <squareBumper name="Square" x="0" y="2" z="9" /> <circleBumper name="Circle" x="4" y="3" z="9" /> <triangleBumper name="Tri" x="1" y="1" z="9" orientation="270" /> <leftFlipper name="FlipL" x="10" y="7" z="9" orientation="0" /> <rightFlipper name="FlipR" x="12" y="7" z="9" orientation="0" /> <absorber name="Abs" x="0" y="19" z="9" width="20" height="1" depth="1" /> </gizmos> <connections> <connect sourceGizmo="Square" targetGizmo="FlipL" /> <keyConnect key="32" keyDirection="up" targetGizmo="Abs" /> </connections> </board>

The ball tag specifies the initial position and velocity of the ball. Because the ball can be at intermediate points within a particular square, the coordinates are specified as floating point numbers. For example:

 <ball name="Ball" x="1.8" y="4.5" z="9.5" xVelocity="-3.4" yVelocity="-2.3" zVelocity="0.0" />
places a ball with name Ball, center at (1.8,4.5,9.5), and an initial velocity of 3.4L per second to the left and 2.3L per second upward.

Each gizmo has a name and a location (x, y, and z coordinates) where it will be placed. The triangleBumper and the flippers all require an orientation. This orientation can be "0", "90", "180", or "270" degrees, and refers to the clockwise rotation of the gizmo in the XY Plane.

Triggers can be connected to actions with the connect tag. In the example above, FlipL's action will be triggered whenever the ball hits the bumper named Square.

The keyConnect tag specifies that the action of a gizmo is associated with a particular key being pressed or released. For example:

        <keyConnect key="32" keyDirection="up" targetGizmo="Abs" />
specifies that the gizmo named "Abs" should be activated whenever the space bar key is released ("32" is the decimal number that represents a space in ASCII). Type man ascii and scroll down to the "Decimal" section to view all the mappings from decimal numbers to ASCII characters).

Because you might also want to allow the outer walls to trigger various actions, the special identifier "OuterWalls" is reserved for it:

        <connect sourceGizmo="OuterWalls" targetGizmo="GIZ" />
This command would cause the ball hitting any of the outer walls trigger the action of the gizmo named by "GIZ".

The main board tag can optionally take arguments for gravity and friction. If the board was described with:

        <board xGravity="0.0" yGravity="16.0" zGravity="0" friction1="0.0" friction2="0.0">
the gravity in the game would be reduced to only (0,16,0) L/sec2 and all effects of friction would be removed.

Here are the contents of the Gizmoball file for the example shown at the beginning of this document. It specifies a triangular bumper in the upper-right-back corner, a bunch of circular and square bumpers, and a few flippers. The actions of the upper flippers are triggered by the "space" (ASCII 32) key, the actions of the lower flippers are triggered by the "q" (ASCII 81) and "w" (ASCII 87) keys, and also by hitting some of the circular bumpers. The action of the absorber is triggered both by the "delete" key (ASCII 127) and also by the absorber itself! This allows the game to run continuously. Every time the ball hits the absorber, the absorber immediately shoots the ball back upwards again.

<board>
 <ball name="Ball" x="1.0" y="11.0" z="9.75" xVelocity="0.0" yVelocity="0.0" zVelocity="0.0"/>
 <gizmos>
  <squareBumper name="S02"  x="0"  y="2" z="9" />
  <squareBumper name="S12"  x="1"  y="2" z="9" />
  <squareBumper name="S22"  x="2"  y="2" z="9" />
  <squareBumper name="S32"  x="3"  y="2" z="9" />
  <squareBumper name="S42"  x="4"  y="2" z="9" />
  <squareBumper name="S52"  x="5"  y="2" z="9" />
  <squareBumper name="S62"  x="6"  y="2" z="9" />
  <squareBumper name="S72"  x="7"  y="2" z="9" />
  <squareBumper name="S82"  x="8"  y="2" z="9" />
  <squareBumper name="S132" x="13" y="2" z="9" />
  <squareBumper name="S142" x="14" y="2" z="9" />
  <squareBumper name="S152" x="15" y="2" z="9" />
  <squareBumper name="S162" x="16" y="2" z="9" />
  <squareBumper name="S172" x="17" y="2" z="9" />
  <squareBumper name="S182" x="18" y="2" z="9" />
  <circleBumper name="C43"   x="4"  y="3" z="9" />
  <circleBumper name="C54"   x="5"  y="4" z="9" />
  <circleBumper name="C65"   x="6"  y="5" z="9" />
  <circleBumper name="C76"   x="7"  y="6" z="9" />
  <circleBumper name="C99"   x="9"  y="9" z="9" />
  <circleBumper name="C109"  x="10" y="9" z="9" />
  <circleBumper name="C1110" x="11" y="10" z="9" />
  <circleBumper name="C129"  x="12" y="9" z="9" />
  <circleBumper name="C139"  x="13" y="9" z="9" />
  <circleBumper name="C156"  x="15" y="6" z="9" />
  <circleBumper name="C165"  x="16" y="5" z="9" />
  <circleBumper name="C174"  x="17" y="4" z="9" />
  <circleBumper name="C183"  x="18" y="3" z="9" />
  <triangleBumper name="T" x="19" y="0" z="9" orientation="90" />
  <triangleBumper name="T2" x="1" y="1" z="9" orientation="0"  />
  <leftFlipper  name="LF92"  x="9"  y="2" z="9" orientation="0" />
  <rightFlipper name="RF112" x="11" y="2" z="9" orientation="0" />
  <leftFlipper  name="LF87"  x="8"  y="7" z="9" orientation="0" />
  <rightFlipper name="RF137" x="13" y="7" z="9" orientation="0" />
  <absorber name="A" x="0" y="19" z="9" width="20" height="1" depth="1" />
 </gizmos>
 <connections>
  <connect sourceGizmo="C43"   targetGizmo="LF87" />
  <connect sourceGizmo="C54"   targetGizmo="LF87" />
  <connect sourceGizmo="C65"   targetGizmo="LF87" />
  <connect sourceGizmo="C76"   targetGizmo="LF87" />
  <connect sourceGizmo="C109"  targetGizmo="LF87" />
  <connect sourceGizmo="C1110" targetGizmo="LF87" />
  <connect sourceGizmo="C139"  targetGizmo="LF87" />
  <connect sourceGizmo="C99"   targetGizmo="RF137" />
  <connect sourceGizmo="C1110" targetGizmo="RF137" />
  <connect sourceGizmo="C129"  targetGizmo="RF137" />
  <connect sourceGizmo="C156"  targetGizmo="RF137" />
  <connect sourceGizmo="C165"  targetGizmo="RF137" />
  <connect sourceGizmo="C174"  targetGizmo="RF137" />
  <connect sourceGizmo="C183"  targetGizmo="RF137" />
  <connect sourceGizmo="A"     targetGizmo="A" />
  <keyConnect key="32"  keyDirection="down" targetGizmo="LF92" />
  <keyConnect key="32"  keyDirection="up"   targetGizmo="LF92" />
  <keyConnect key="32"  keyDirection="down" targetGizmo="RF112" />
  <keyConnect key="32"  keyDirection="up"   targetGizmo="RF112" />
  <keyConnect key="87"  keyDirection="down" targetGizmo="RF137" />
  <keyConnect key="87"  keyDirection="up"   targetGizmo="RF137" />
  <keyConnect key="127" keyDirection="down" targetGizmo="A" />
  <keyConnect key="81"  keyDirection="down" targetGizmo="LF87" />
  <keyConnect key="81"  keyDirection="up"   targetGizmo="LF87" />
 </connections>
</board>

Semantics

We now describe each element defined in the specification, in turn.
<board xGravity="FLOAT" yGravity="FLOAT" zGravtiy="FLOAT" friction1="FLOAT" friction2="FLOAT">
Defines a board. There must be exactly one of these tags in a valid Gizmoball level file. The gravity of the board is set to (xGravity,yGravity,zGravity) L/sec2 with a default of (0,25,0). The global friction constants are set such that mu and mu2 (as described in the friction formula) are friction1 and friction2, respectively (both have a default value of 0.025).
The board tag encloses zero or one ball tags, followed by a gizmos tag and a connections tag.
<ball name="STRING" x="FLOAT" y="FLOAT" z="FLOAT" xVelocity="FLOAT" yVelocity="FLOAT" zVelocity="FLOAT" />
Creates a ball whose center is (x,y,z) and whose velocity is (xVelocity, yVelocity, zVelocity). Within the file, the name must be unique, and may be used later to refer to this specific ball. Note that you are not required to support nonzero zVelocity.
<gizmos />
The gizmos tag is just used as a container for zero or more gizmos (squareBumper, circleBumper, triangleBumper, rightFlipper, leftFlipper, and absorber). It takes no attributes.
<squareBumper name="STRING" x="INTEGER" y="INTEGER" z="INTEGER" />
<circleBumper name="STRING" x="INTEGER" y="INTEGER" z="INTEGER" />
<triangleBumper name="STRING" x="INTEGER" y="INTEGER" z="INTEGER" orientation="0|90|180|270" />
<rightFlipper name="STRING" x="INTEGER" y="INTEGER" z="INTEGER" orientation="0|90|180|270" />
<leftFlipper name="STRING" x="INTEGER" y="INTEGER" z="INTEGER" orientation="0|90|180|270" />
Creates the given gizmo with its upper-left-front at (x,y,z) and with the given orientation. Within the file, the name must be unique, and may be used later to refer to this specific gizmo. The "0" orientation for each orientable gizmo is:
triangleBumper
One corner in the top-right, one corner in the top-left, and the last corner in the bottom-left. The diagonal goes from the bottom-left corner to top-right corner.
leftFlipper
pivot in left-top corner, other end in left-bottom corner
rightFlipper
pivot in top-right corner, other end in bottom-right corner
When specified, the orientation attributed indicates a clockwise rotation in the XY Plane of the whole gizmo compared to its default orientation.
<absorber name="STRING" x="INTEGER" y="INTEGER" z="INTEGER" width="INTEGER" height="INTEGER" depth="INTEGER"/>
Creates an absorber with its upper-left-front corner at (x,y,z) that is width wide, height tall, and depth deep. width, height, and depth must all be greater or equal to 1 and must not cause the absorber to extend off of the board. Within the file, the name must be unique, and may be used later to refer to this specific absorber.
<connections />
A tag that has no attributes. It is just a container for zero or more connections and keyConnections.
<connect sourceGizmo="STRING" targetGizmo="STRING" />
Makes the gizmo named by targetGizmo a consumer of the triggers produced by the gizmo described by sourceGizmo. That is, every time a ball hits sourceGizmo, targetGizmo's action will happen.
<keyConnect key="INTEGER" keyDirection="down" targetGizmo="STRING" />
<keyConnect key="INTEGER" keyDirection="up" targetGizmo="STRING" />
Makes the item named by targetGizmo a consumer of the trigger produced when the key represented by key is pressed (or released, respectively).

The formal definition of the file format can be found in the schema gb_level.xsd.  Basically, the schema defines which elements it expects to see in an XML file and notes where the format may be extended.  (These extension points are denoted by either <xs:any> or <anyAttribute>.)  You don't have to understand the schema unless you want to extend it to support any new Gizmoball features you've designed.  If you want to extend the schema, the XML Schema Tutorial will be helpful.

Appendix 3: The physics package

General

The provided physics library consists of immutable abstract data types such as Angle, Vect3, Line, and PlaneCircle, as well as a class Geometry3D that contains static methods to model the physics of elastic collisions between balls and other circles and line segments. You are welcome to use or not use this code as you please, and to modify it to meet your needs.

Documentation for the physics3d package can be found in here.

A cookbook for learning how to use the physics library can be found here.

While this source is provided in the event that you wish to examine or modify it, we strongly discourage you from modifying it. In the past, students who have not used the physics library as-is have had poor results on their projects. Most groups will not need to copy the source code to their own directories, add it to their CVS repositories, or compile it, but will just use the gb-lib.jar file and examine the specifications.

If you believe there is an error in the physics engine, feel free to email the TA's. Please include in your email the function in question, the input, the output you expect, and the output you actually got.

Tips for Full 3D Physics

If you plan on supporting three dimensional physics, an option might be to:

These changes let gizmoball simulate a 3d pinball machine that is tilted such that the balls go towards the ground and back (away from you). Note that you might not want to change the default gravity vector for 2d maps since, with this particular change, gizmos (and balls) that aren't on the z = 9 (z=9.75) plane will not stay in their z plane.

Errata

April 16:
Uploaded the opengl demo. Clarified that JAWS was required for both the prelim and the final release.
April 22:
April 29:
In Geometry3D.java, the line
Vect3 inward = pOnLine.minus(newCenter).unitSize()...
should actually be
Vect3 inward = newPOnLine.minus(newCenter).unitSize()...
We have updated gb-lib.jar accordingly. This bug only affected groups with non-zero zVelocity
May 3:
Added hint about XML validation.
May 6: