CS1321L Homework 9
Due: Monday, November 14 at 8:00 pm

Introduction

This assignment will give you some experience working with classes, subclasses, interfaces, polymorphism and dynamic binding. You will develop some classes that will be interrelated via has-a and is-a relationships. The program will have you develop a simple simulation in which the classes you create are used to by a third party driver (main) program. This assignment is relatively open-ended so you shoudl be creative and have some fun with it.

Here Fishy, Fishy

In this program you will develop a simple aquarium simulation. The aquarium will be modeled by a class itself, and then each of the objects inside it will have their own class too. We will set up specific methods for each class that you must implement.

To begin, an aquarium is a rectangle with water inside. (We suggest a color like (109, 171, 177) for a nice sea blue.) An aquarium should simply be a subclass of a JFrame. Aquariums hold a number of background-style objects such as sand, plants, and aerators. We will create an interface that models background objects and each such object must implement this interface. An aquarium then will also have an addObject() method that affiliates one of these objects with the aquarium. Finally, the aquarium will have a refresh() method that redraws the aquarium in the following order: First redraw the background, then draw each object in the order they were added. This effectively wipes clean everything that was there before.

Here are the respective classes, interfaces and methods that you must implement. Feel free to add any methods that you want. The ones listed here are only the minimal subset that must be provided.

public class Aquarium extends JFrame {
   public Aquarium(int width, int height)
   public Color getWaterColor()
   public Dimension getSize()
   public Graphics getGraphicsContext()
   public void addObject(AquariumObject ao)
   public void refresh()
}

Here is the interface for an AquariumObject. Its source code is in the file AquariumObject.java

public interface AquariumObject {
   public void paint(Graphics g);
}

Here are three AquariumObjects that you must create. Also, feel free to create any other AquariumObject classes that you would like to add to make your aquarium look good.

public class Sand implements AquariumObject {  // Simulates the
             // gravel or sand that sits on the bottom of an aquarium

   public Sand(int x, int y, int width)  // The parameters specify
         // the bottom-center position of the sand within its
         // graphical context and the width specifies how wide it
         // should be.  It should be relatively short too.
   public void paint(Graphics g)   // Redraw the sand
}


public class UnderwaterPlant implements AquariumObject {  // Represents
              // a plant.  Feel free to make each one created have its
              // own unique appearance.

   public UnderwaterPlant(int x, int y, int width, int height)
       // The x and y parameters denote the bottom center coordinate
       // of the plant.  The width and height denote the maximum size
       // this plant can be (smaller is OK).
   public void paint(Graphics g)   // Redraw the plant
}


public class Aerator implements AquariumObject {  // Represents an
            // aquarium air bubbler

   public Aerator(int x, int y, int height)   // The x and y parameters
       // denote the bottom center position of the aerator and the 
       // height parameter specifies how high the bubbles should go
       // above that coordinate.
   public void paint(Graphics g)    // Redraw the aerator.  NOTE:
       // subsequent class to paint should slightly change the
       // positions of bubbles so it looks like the aerator is running
       // and sending bubbles up to the surface.
}

OK, now that we've dealt with the background elements, we can provide the more fun elements, the aquarium's inhabitants. Your aquarium can have both crabs and fish. For crabs, there will be one simple crab class.

For fish, we will have a superclass Fish that represents a stationary fish. There are two constructors. One is more tightly specified and the other is designed to be more random and free. Fish will have a subclass MovingFish that has the ability to swim around to different positions. The call setBounds() on Moving Fish is important to define the edges of the aquarium that they should bump up against but not go outside. The important difference on a MovingFish is that each subsequent call to paint() should slightly move the fish to a different position, thus giving the impression that the fish is swimming. Think about how fish move---don't just have it randomly wiggle. Be creative.

public class Crab implements AquariumObject {
   public Crab(int x, int y)  // The x and y parameters denote the 
         // bottom-center of the crab.  You can make it some arbitrary
         // (possibly random) reasonable size.
   public void paint(Graphics g)   // Draw the crab
}

public class Fish implements AquariumObject {
   public Fish(Color c, Polygon p, int x, int y)  // Use the
         // specified polygon as the fish outline.  The coords are
         // relative to the x,y.  Make it the given solid color.
   public Fish(int x, int y)   // Create some random (but decent)
         // looking fish at the given position
   public void paint(Graphics g)   // Draw the fish
}

public class MovingFish extends Fish implements AquariumObject {
   public MovingFish(Color c, Polygon p, int x, int y)  // Use the
         // specified polygon as the fish outline.  The coords are
         // relative to the x,y.  Make it the given solid color.
   public MovingFish(int x, int y)   // Create some random (but decent)
         // looking fish at the given position
   public void setBounds(int minx, int miny, int maxx, int maxy)  // Defines
         // the boundaries for swimming
   public void paint(Graphics g)   // Draw the fish
}   

Feel free to define your own subclasses of Fish and/or MovingFish. You might create an AngelFish, CatFish or some such animal that has its own unique look and behavior. You can add more methods to these and the superclasses too, but they objects should be able to run using only the ones specified above as a minimal, but sufficient, subset.

In testing your program, we will use two example driver classes with main() in them. In the first, we will design a basic driver that looks much like the example below. This will test the basic minimal, functionality of your program. Source code for this file can be found in AquariumTest.java

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AquariumTest {
   private final int DELAY = 20;
   private Aquarium aquarium;
   private Crab crab;
   private Fish[] fish;
   private Graphics g;
   private Timer timer;
   private int count = 0;

   public static void main(String[] args) {
       AquariumTest at = new AquariumTest();
       at.start();
   }

    public void start() {
      int[] x = {0, 30, 40, 50, 60, 70, 90, 100, 115,
                 130, 115, 100, 90, 70, 60, 50, 40, 30, 0, 15};
      int[] y = {5, 15, 10, 7, 0, 7, 12, 15, 22, 25, 28, 35, 40,
                 43, 50, 43, 40, 35, 45, 25};

      aquarium = new Aquarium(800,600);
      g = aquarium.getGraphicsContext();

      Sand s = new Sand(400,600,800);
      aquarium.addObject(s);
 
      UnderwaterPlant p = new UnderwaterPlant(120, 580, 30, 300);
      aquarium.addObject(p);

      Aerator a = new Aerator(700, 550, 550);
      aquarium.addObject(a);

      aquarium.refresh();

      crab = new Crab(380, 590);
      Polygon poly = new Polygon(x, y, x.length);
      fish = new Fish[4];
      fish[0] = new Fish(280, 120);
      fish[1] = new Fish(new Color(234,200,167), poly, 560, 400);
      fish[2] = new MovingFish(315, 567);
      ((MovingFish)fish[2]).setBounds(0,0,800,600);
      fish[3] = new MovingFish(new Color(214,30,230), poly, 700, 120);
      ((MovingFish)fish[3]).setBounds(0,0,800,600);

      timer = new Timer(DELAY, new AnimListener());
      timer.start();
    }

    public void nextFrame() {
       aquarium.refresh();
       crab.paint(g);
       for (int i=0; i<fish.length; i++)
          fish[i].paint(g);
    }

    private class AnimListener implements ActionListener {

        public void actionPerformed(ActionEvent ae) {
           nextFrame();

           count++;
           if (count == 1000) 
              timer.stop();
        }
    }
}

The second should be created by you. Call your class AquariumSimulation. In it, you should show off all the interesting and different features you added. For instance, you might create instances of any fish subclasses you created. Have fun with this one!

Turn-in Procedures

After you have finished your program, turn the files in via Webwork You will be submitting multiple files. Please make sure they are named as shown below:

  • Aquarium.java
  • AquariumObject.java
  • UnderwaterPlant.java
  • Sand.java
  • Aerator.java
  • Fish.java
  • MovingFish.java
  • AquariumSimulation.java
  • Any other classes that you create for use in the assignment