6.031 — Software Construction
Fall 2017

Flingball Specification (Phase 1)

Playing Area

To describe dimensions in the playing area, we define L to be the basic distance unit, equal to the edge length of a square bumper. Corresponding to standard usage in the graphics community, the origin is in the upper left-hand corner with coordinates increasing to the right and down.

The playing area must be 20 L wide by 20 L high. That is, 400 square bumpers could be placed on the playing area without overlapping. The upper left corner is (0,0) and the lower right corner is (20,20). When we say a gadget is at a particular location, that means that the gadget’s origin is at that location. The origin of each of the gadgets is the upper left-hand corner of its bounding box, so the location furthest from the origin at which a gadget may be placed is (19,19) on a 20L × 20L board. In contrast, the origin of a ball is at its center.

Gadgets

A Flingball game has gadgets on the playing area, such as bumpers. The gadgets that must be supported in phase 1 are described in this section.

A gadget has an (x,y) location, where x and y are integers in [0,19] (unless otherwise stated).

A gadget has a width and height, also integers in [0,19] (again, unless otherwise stated). Some gadgets have a fixed width and height (like bumpers), and others have a configurable width and height (like absorbers).

Some gadgets have a coefficient of reflection, which is a multiplier applied to the magnitude of the ball’s velocity after it bounces off the gadget. Coefficient 1.0 means that the ball leaves the bumper with the same velocity with which it hit the bumper, but in a different direction. Coefficients less than 1.0 damp the ball’s velocity, and coefficients greater than 1.0 increase it. By default, all bumpers have reflection coefficients of 1.0, but you can optionally extend Flingball to allow different coefficients to be specified.

Some gadgets have an orientation, which determines how the gadget is rotated from its default orientation. Orientation may be 0 degrees (the default orientation), 90 degrees, 180 degrees, or 270 degrees. When orientation is 90, 180, or 270 degrees, the value indicates a clockwise rotation in degrees of the whole gadget from the default orientation, around the center of the bounding box of the gadget (not around the (x,y) origin point of the gadget).

Each gadget may have a trigger and an action. A trigger is an event that happens at the gadget, such as a ball colliding with it. An action is a response that a gadget can make to a trigger happening somewhere on the board. A gadget’s action can be hooked up to another gadget’s trigger, in order to produce Rube Goldberg machines. A gadget’s action can also be hooked up to its own trigger, so that it triggers itself.

Square Bumper

Size and shape
a square shape with edge length 1L
Orientation
not applicable (symmetric to 90 degree rotations)
Coefficient of reflection
1.0
Trigger
generated whenever the ball hits it
Action
none

Circle Bumper

Size and shape
a circular shape with diameter 1L
Orientation
not applicable (symmetric to 90 degree rotations)
Coefficient of reflection
1.0
Trigger
generated whenever the ball hits it
Action
none

Triangle Bumper

Size and shape
a right-triangular shape with sides of length 1L and hypotenuse of length Sqrt(2)L
Orientation
the default orientation (0 degrees) places one corner in the northeast, one corner in the northwest, and the last corner in the southwest. The diagonal goes from the southwest corner to the northeast corner.
Coefficient of reflection
1.0
Trigger
generated whenever the ball hits it
Action
none

Absorber

Size and shape
A rectangle kL wide and mL tall, where k and m are positive integers <= 20
Orientation
not applicable (only one orientation is allowed)
Coefficient of reflection
not applicable; the ball is captured
Trigger
generated whenever the ball hits it
Action
shoots out a stored ball (see below)

An absorber simulates the ball-return mechanism in a pinball game. When a ball hits an absorber, the absorber stops the ball and holds it (unmoving) in the bottom right-hand corner of the absorber. The ball’s center is .25L above the bottom of the absorber and .25L left of the right side of the absorber. The absorber can hold any number of balls in this location.

If the absorber is holding at least one ball, then the action of an absorber, when it is triggered, is to shoot one ball straight upwards in the direction of the top of the playing area. The initial velocity of the ball should be 50L/sec. 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 a 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.

An absorber can be made self-triggering by connecting its trigger to its own action. When the ball hits a self-triggering absorber, it should be moved to the bottom right-hand corner as described above, and then be shot upward as described above. There may or may not be a short delay between these events, at your discretion, but a ball that hits a self-triggering absorber must always leave the absorber.

Outer Walls

The border walls surrounding the playfield.

Coefficient of reflection
1.0
Trigger
none
Action
none

A Flingball game supports exactly one set of outer walls, which lie just outside the playing area:

  • one horizontal wall just above the y=0L coordinate
  • one horizontal wall just below the y=20L coordinate
  • one vertical wall just to the left of the x=0L coordinate
  • one vertical wall just to the right of the x=20L coordinate

Flingball Physics

The animation grid may be no coarser than 0.05 L by 0.05 L. Suppose that a ball is at (1,1) and is moving in the (1,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), (1.05,1), and (1.10,1), and can be displayed at more positions if you wish the animation to be smoother. If the ball is moving faster than the animation grid size per frame redraw, it need not be redrawn in each animation grid position.

The ball by default must have a diameter of approximately 0.5L. Ball velocities must range at least from 0.01 L/sec to 200 L/sec and can cover a larger range if you wish. 0 L/sec (stationary) must also be supported. An acceptable frame rate should be used to generate a smooth animation. We have found that 20 frames per second tends to work well across a reasonably wide range of platforms.

The ball should interact reasonably with the playing area. That is, the ball should bounce in the direction and with the resulting velocity that you would expect it to bounce in a physical pinball game.

Balls may either interact with other balls or ignore them, at the discretion of the implementer.

The velocity of the ball should continually change to account for the effects of gravity. The default gravity value should be 25 L/sec2, which resembles a pinball game with a slightly tilted playing surface, but your Flingball boards should be able to be configured with a different value for gravity.

The ball velocity should also continually change to account for the effects of friction. You should model friction by scaling the velocity of the ball using the frictional constants mu and mu2. For sufficiently small deltat's you can model friction as Vnew = Vold × ( 1 - mu × deltat - mu2 × |Vold| × deltat ). The default value of mu should be 0.025 per second. The default value of mu2 should be 0.025 per L. Flingball boards should be able to be configured with different values for mu and mu2.

Graphical User Interface

Your Flingball client should display the running game as a graphical user interface that pops up in a new window. The appearance of this window is up to you, but it should display the full 20L x 20L board with all its gadgets, and display gadgets using appropriate geometric shapes, e.g., balls should be circles, triangle bumpers should be triangles, etc. Balls should animate as smoothly as possible.

Flingball File Format

The configuration of a Flingball board can be read from a file. By convention, Flingball board files end with .fb. Please use this convention in your repository so that your TA can easily find your example boards.

Several sample board files have been provided. There are also example videos showing what these boards might look like when run, but your implementation will look different, not only because this spec offers a great deal of design freedom, but also because the videos themselves are unfaithful renderings of that example implementation, with missing frames, uneven framerate, and unevenly cropped window edges, among other visual differences. The videos are not part of this spec.

You should write a ParserLib grammar to read in board files in the format described below.

The following is an example of a very simple Flingball board file:

board name=Example

# define a ball
ball name=Ball x=1.8 y=4.5 xVelocity=-3.4 yVelocity=-2.3 

# define some bumpers
squareBumper name=Square x=0 y=2
circleBumper name=Circle x=4 y=3
triangleBumper name=Tri x=1 y=1 orientation=270

# define an absorber to catch the ball
absorber name=Abs x=0 y=19 width=20 height=1 

# define events between gadgets
fire trigger=Square action=Abs

# also make the absorber self-triggering
fire trigger=Abs action=Abs 

Each command in the file, like the definition of a ball or bumper, is described by a single line in the file. Whitespace at the start or end of lines is irrelevant. Extra whitespace between tokens of a line (words or =) are not important. Lines that are blank, or lines that start with a #, are ignored. All lines end with a newline, including the last line in the file.

# this is a comment

   # this is also comment

The specification below refers to integers, floating point numbers, and names, which are specified as follows:

    INTEGER ::= [0-9]+
    FLOAT ::= -?([0-9]+.[0-9]*|.?[0-9]+)
    NAME ::= [A-Za-z_][A-Za-z_0-9]*

We now describe each kind of line that may appear in the board file.

    board name=NAME (gravity=FLOAT)? (friction1=FLOAT)? (friction2=FLOAT)?

Defines a board. This line must be the first non-comment line in a valid Flingball board, and exactly one board line must appear in the file.

The gravity, friction1, and friction2 parameters in the board line are all optional, but should appear in the order given. The gravity is interpreted as L/sec2 in the downward direction. If omitted, the default gravity is 25.0. The global friction constants are set such that mu and mu2 (as described in the friction formula) are friction1 and friction2, respectively. If either one is omitted, its default value is 0.025.

    ball name=NAME x=FLOAT y=FLOAT xVelocity=FLOAT yVelocity=FLOAT

Creates a ball whose center is (x,y) and whose velocity is (xVelocity, yVelocity). Within the file, the name must be unique, and may be used later to refer to this specific ball.

    squareBumper name=NAME x=INTEGER y=INTEGER
    circleBumper name=NAME x=INTEGER y=INTEGER
    triangleBumper name=NAME x=INTEGER y=INTEGER (orientation=0|90|180|270)?

Creates the given gadget with its upper left-corner at (x,y) and with the given orientation. Within the file, the name must be unique, and may be used later to refer to this specific gadget. Consider the names of gadgets (e.g., squareBumper, circleBumper) and any other variable names to be reserved. For example, you do not need to support “ball name = ball”, or “squareBumper name = squareBumper”.

For triangleBumper, the orientation parameter is optional, and defaults to 0 if not given.

    absorber name=NAME x=INTEGER y=INTEGER width=INTEGER height=INTEGER

Creates an absorber with its upper left-hand corner at (x,y) that is width wide and height tall. width and height must both be greater than 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.

    fire trigger=NAME action=NAME

Makes the gadget named by action a consumer of the trigger events produced by the gadget named by trigger. For example, if trigger names a bumper and action names an absorber, then every time a ball hits the bumper, the absorber will fire the ball it is holding. A gadget can be a trigger for the actions of multiple gadgets, and a gadget’s action can be triggered by multiple gadgets. A gadget can also trigger its own action. For example, an absorber that triggers its own action would be used to make a perpetual pinball game that automatically shoots out the ball whenever it falls into the absorber.

Main Program

Your program should have a main method in a class called Flingball.java. The package structure of the project is up to you, but make it sensible so that your TA can find your main program easily.

Your Flingball program should take an optional command-line argument, the name of a board file to load and run:

Flingball FILE?

FILE is an optional argument specifying a file pathname of the Flingball board that this client should run. If FILE is not provided, then your Flingball client should display the default.fb benchmark board included in the starting code.

There are several ways to run a Java program with command-line arguments.