CSE 160
HW 11
Due May 7, 2009


Reading:
For this week, review the BouncingBall demo and Canvas class described on pp. 150-155 of the text and read the online Java Tutorial on Graphics2D.  Read Chapter 12 in the Objects First text (on Exceptions).  Work along with it, using BlueJ.

HW: We return to the JukeBox project to add a graphical component. We will discuss the design in class.  This is complex, so do not put it off for the last minute.

Key points: The text does not have a chapter on Graphics2D, so here are some essentials to note when studying the above examples:

Any JPanel can provide a Graphics object, with its getGraphics() method.  The contentPane of a JFrame can be used for Graphics if you want to fill the frame with graphics.  Usually one uses a smaller JPanel somewhere lower down in the containment hierarchy.

You can cast the Graphics object to the newer Graphics2D type and use the following methods. Some methods immediately draw graphical objects, e.g., rectangles, ellipses, text, images.  Other methods set attributes which affect subsequent drawing, e.g., color, pen width, font, and are remembered until changed later. Here are some examples to look up in the JavaDocs:
The Shape type (it is an Interface) includes lines, rectangles, elliupses, and arbitrary polygons, which are described by a sequence of vertex coordinates.  Look up Line2D.Double, Ellipse2D.Double, Polygon, and Rectangle.

[This Canvas approach does not involve a repaint() method to redraw the contents when necessary, e.g., when a window in front of our window is moved away.  And this method does not involve double buffering, in which a copy of the image is kept to be automatically redrawn when needed.  So the panel will go blank if resized or uncovered, but that is OK as you will be continuously repainting over it. Next semester, you will see more sophisticated ways to do animation, with multiple threads.]

JukeBox Graphics

Here is a sketch of a possible design, which we will discuss in class.  You may prefer your own design.  Anything that works is fine. You do not need to make the switch animate back and forth, but you can do so for extra credit, so ignore those parts below unless you have finished everything else.

Constructors for Tube, Bucket, and Switch class take additional parameters which indicate the (x,y) location, size, and color of their graphical representation.  An animate() method to the Switch is called at regular intervals by the Game, causing it to update to its next position, among a series of angles from left to right.

There is a Location class which can hold a Ball. Each Ball knows its Location, and each Location knows what Ball it contains (or holds null if there is no ball at that location). Each Location nas a next() method which returns the following Location. For example, a Tube may have five or so Locations along its length, each pointing to the next lower one, with the last one pointing to the first location of its outlet.  At regular intervals, a move() method in each Ball causes it to attempt to move to the next location after its current location, but if that location is not ready, this ball just waits. Each Location has a isReady() method which returns false if it already contains a ball or is in a switch that is in motion between its left and right angles.

Work with graph paper to lay out your graphical design.  One can generate a Polygon something like the shape of the switches in the online game like the following, but some sines and cosines would allow for a rounder shape and this does not have adjustable size pockets:

    {
        Polygon p = new Polygon();
        p.addPoint(0, -50);
        p.addPoint(-30, -40);
        p.addPoint(-10, -20);
        p.addPoint(-20, -10);
        p.addPoint(-40, -30);
        p.addPoint(-50, 0);
        p.addPoint(-40, 40);
        p.addPoint(0, 50);
        p.addPoint(40, 40);
        p.addPoint(50, 0);
        p.addPoint(40, -30);
        p.addPoint(20, -10);
        p.addPoint(10, -20);
        p.addPoint(30, -40);
        p.addPoint(0, -50);
        p.translate(100,160);
        return p;
    }

You may want methods to scale a polygon, and to translate a polygon by adding (x,y) to each coordinate.  You can write a method to rotate a polygon about the origin by an angle theta, that calculates for each (x,y) an new (x', y') by the formulas:

x' = Cos(theta) * x + Sin(theta) * y
y' = Sin(theta) * x - Cos(theta) * x

Addenda:

Here are some design ideas that can be made to work without too much coding.  As always, feel free to go with your own design ideas if you prefer.

The abstract Receiver class can have two methods: receive(Ball) and isReady(). It can have four subclasses: Tube, Switch, Bucket, and Location.  The Location class can have four fields: x, y, a Ball, and a Receiver outlet. The outlet is where the Ball goes after here, or null if this is a dead end, e.g., the bottom of a Pocket that faces up. 

When a Tube is created, it creates a series of Locations within it. Each points to the next in line.  The last points to the tube's outlet. When a Tube receives a ball, it just passes it to the top Location in the Tube.  Similarly, when a tube is asked if it is ready, it just passes along the response from it's top Location's isReady().

A Bucket should always be ready to receive. When it receives a ball it doesn't have to keep it.  So it can put it in a location (which should delete it from the previous location) and then set the ball field to null.

The Switch is the tricky part. It should create two Pockets, each of which creates a series of one to three Locations, as in a tube. A pocket has a faceUP() method and a faceDown() method. The faceUP() method causes each of its locations to set its outlet to be to the next one below it, except the bottom one has no outlet. The faceDown() method causes the outlets to go in the other direction, with the first one pointing to the Pocket's outlet. When the Switch changes state, the Pocket which was facing up is told to faceDown and vice versa.  You don't need to animate your switch and pockets (that is extra credit) but indicate somehow, e.g., with color, what state they are in.

You can have an isEmpty() and an isFull() method for the Pockets. The switch changes state when the top pocket is full and the bottom one is empty.  The Switch is ready to receive if its top pocket is ready to receive, and a pocket is ready if it's initial location is ready.

If you are having trouble, don't animate the Switch class; just have it change instantly between its LEFT state and its RIGHT state.  If you want the Switch class to be animated, it needs a state field with four states: L, R, MOVING_L, and MOVING_R. When told to animate, it should move further if it is moving; it should stop moving if it reached the maximum angle; it should start moving if the top pocket is full and the bottom pocket is empty.  An angle field, keeps track of the current angle.

The Ball class has a field for its Location.  When a Ball is told to try to move, it checks to see if its Location has a non-null outlet, and if so checks if that outlet is ready to receive.  If so, execute the new location's receive method, causing the new location to store the ball and erase the ball from the current location (if any).

Finally, the Game class creates the buckets, tubes, and switches, giving them their locations, sizes and colors, and putting them into a list of Paintables. (You should have a Paintable interface which specifies a paint() method, analogous to how the foxes and rabbits were collected.)  Then it runs an animation loop, which goes through each of the Paintables and tells them to paint themself; then it sleeps for a while. Whenever a ball is created, it is added to the list of paintables, so it too will be drawn. Wihtin this loop, after painting everything, or every few such times, tell each Ball to try to move. 

Submit your .jar file on May 7.