Computer Science 252
Problem Solving with Java
Spring 2014, The College of Saint Rose
FallingThings Demo
A working demo of FallingThings will appear below. Click inside the applet to interact with it.
FallingThings BlueJ Project
Click here to download a BlueJ project for FallingThings.
FallingThings Source Code
The Java source code for FallingThings is below. Click on a file name to download it.
import objectdraw.*; import java.awt.*; /* * Example FallingThings: an example of the Drawable2DInterface to * generate objects that can fall down the canvas using a generic * active object. * * Jim Teresco, The College of Saint Rose, CSC 252, Spring 2014 * * $Id: FallingThings.java 2329 2014-02-27 02:46:26Z terescoj $ */ public class FallingThings extends WindowController { // the Image objects we'll need to pass to our generators private Image birdImage, knightImage; // begin just loads some images public void begin() { birdImage = getImage("WhiteBird.png"); knightImage = getImage("GoldenKnight.png"); } // Each time we press the mouse, we'll randomly create a // generator for the objects that will fall down the canvas. // We pass in the Image objects for each VisibleImage we // might generate as well public void onMousePress(Location point) { new ItemGenerator(birdImage, knightImage, canvas); } }
/** * An active object that is capable of animating any object type * that implements the Drawable2DInterface interface in Objectdraw. * * @author Jim Teresco */ import objectdraw.*; import java.util.Random; public class FallingThing extends ActiveObject { // settings for a simple constant speed animation private static final int MOVE_BY = 4; private static final int DELAY = 33; // our item to have fall private Drawable2DInterface thing; // the y-coordinate of the bottom of the canvas private double yMax; // constructor remembers a few things, chooses a random // position, places the item just off the top of the canvas // and starts things up public FallingThing(Drawable2DInterface thing, DrawingCanvas c) { // remember what we need to remember for the run method this.thing = thing; yMax = c.getHeight(); // get the item into a random starting position just off the screen Random r = new Random(); double width = thing.getWidth(); double height = thing.getHeight(); double xPos = r.nextDouble() * (c.getWidth() - width); thing.moveTo(xPos, -height); start(); } // the life of this falling object public void run() { while (thing.getY() < yMax) { thing.move(0, MOVE_BY); pause(DELAY); } thing.removeFromCanvas(); } }
/** * An active object that generates, randomly, items to fall down * the canvas using another, generic, active object that can * control the fall of any object that implements the Objectdraw * Drawable2DInterface interface. * * @author Jim Teresco */ import objectdraw.*; import java.awt.*; import java.util.Random; public class ItemGenerator extends ActiveObject { // how many items will each instance generate? private static final int NUM_ITEMS = 100; // we'll need some random numbers private Random r = new Random(); // the images we'll use for some of our objects private Image birdImage, knightImage; // and we'll need to remember our canvas private DrawingCanvas canvas; // the constructor need only remember a few things // and start up the thread public ItemGenerator(Image b, Image k, DrawingCanvas c) { birdImage = b; knightImage = k; canvas = c; start(); } // the run method generates our objects periodically public void run() { // we generate 100 objects per ItemGenerator for (int i = 0; i < NUM_ITEMS; i++) { // A variable that will hold an object to be animated, and // since it can be one of many object types, we declare it // as a Drawble2DInterface. But by doing so, we agree only // to interact with that object only through the methods // specified by that interface. Drawable2DInterface item; // we'll pick a random number that determines which of the many // types of objects actually is going to be created int itemType = r.nextInt(10); switch (itemType) { case 0: item = new FilledRect(0, 0, 50, 50, canvas); item.setColor(Color.red); break; case 1: item = new FilledOval(0, 0, 50, 50, canvas); item.setColor(Color.blue); break; case 2: item = new FramedRect(0, 0, 50, 50, canvas); item.setColor(Color.green); break; case 3: item = new FramedOval(0, 0, 50, 50, canvas); item.setColor(Color.magenta); break; case 4: item = new FilledArc(0, 0, 50, 50, 45, 270, canvas); item.setColor(Color.yellow); break; case 5: item = new Text("I'm falling!", 0, 0, canvas); item.setColor(Color.orange); break; case 6: item = new VisibleImage(birdImage, 0, 0, canvas); break; case 7: item = new VisibleImage(knightImage, 0, 0, canvas); break; case 8: item = new TShirt(0, 0, canvas); break; default: item = new NiceBBall(0, 0, 75, canvas); break; } new FallingThing(item, canvas); pause(500); // generate one every half second } } }
import objectdraw.*; import java.awt.Color; import java.util.Random; /* * A class that implements a nice looking basketball, this one implementing * the Drawable2DInterface from Objectdraw. * * Jim Teresco, The College of Saint Rose, Spring 2014 * * $Id: NiceBBall.java 2329 2014-02-27 02:46:26Z terescoj $ */ public class NiceBBall implements Drawable2DInterface { // the color to draw the ball private static final Color BALL_ORANGE = new Color(250, 85, 10); // size and starting angles for cut arc in degrees private static final int CUTSIZE = 100; private static final int RIGHTCUTSTART = 90 + (180 - CUTSIZE) / 2; private static final int LEFTCUTSTART = 270 + (180 - CUTSIZE) / 2; // the orange part of the ball private FilledOval body; // the border of the ball private FramedOval border; // the two curves on the sides of the ball private FramedArc leftCut, rightCut; // the vertical and horizontal lines through the ball private Line vert, horiz; // to pick new random color for ball private Random colorPicker = new Random(); /* * Create a new basketball on the given DrawingCanvas. Note how this class * does not know about the default "canvas", since that's available only in * classes that extend the WindowController class. */ public NiceBBall(double left, double top, double size, DrawingCanvas aCanvas) { // draw the circles that make it look like a ball body = new FilledOval(left, top, size, size, aCanvas); body.setColor(BALL_ORANGE); border = new FramedOval(left, top, size, size, aCanvas); // draw the lines and arcs that make it look like a basketball rightCut = new FramedArc(left + size * 2 / 3, top, size, size, RIGHTCUTSTART, CUTSIZE, aCanvas); leftCut = new FramedArc(left - size * 2 / 3, top, size, size, LEFTCUTSTART, CUTSIZE, aCanvas); vert = new Line(left + size / 2, top, left + size / 2, top + size, aCanvas); horiz = new Line(left, top + size / 2, left + size, top + size / 2, aCanvas); } /* * Move the ball by specified offsets. */ public void move(double dx, double dy) { // move each part of the ball by the offsets provided body.move(dx, dy); border.move(dx, dy); vert.move(dx, dy); horiz.move(dx, dy); leftCut.move(dx, dy); rightCut.move(dx, dy); } /* * Check to see if the ball contains a specified location. */ public boolean contains(Location point) { return body.contains(point); } /* * Move the ball to a specified position. */ public void moveTo(double x, double y) { // determine how far away (x,y) is double dx, dy; dx = x - body.getX(); dy = y - body.getY(); // move each part of the ball by the offset, // using our own move method. this.move(dx, dy); } /* * Return the x coordinate of ball's corner. */ public double getX() { return body.getX(); } /* * Return the y coordinate of ball's corner. */ public double getY() { return body.getY(); } // we are required by Drawable2DInterface to provide an overlaps method // which just checks if the "body" here overlaps the other public boolean overlaps(Drawable2DInterface other) { return body.overlaps(body); } // getLocation required by Drawable2DInterface public Location getLocation() { return body.getLocation(); } // we also must provide getWidth and getHeight public double getWidth() { return body.getWidth(); } public double getHeight() { return body.getHeight(); } // also stacking order methods public void sendToFront() { body.sendToFront(); border.sendToFront(); rightCut.sendToFront(); leftCut.sendToFront(); vert.sendToFront(); horiz.sendToFront(); } public void sendToBack() { border.sendToBack(); rightCut.sendToBack(); leftCut.sendToBack(); vert.sendToBack(); horiz.sendToBack(); body.sendToBack(); } public void sendBackward() { border.sendBackward(); rightCut.sendBackward(); leftCut.sendBackward(); vert.sendBackward(); horiz.sendBackward(); body.sendBackward(); } public void sendForward() { border.sendForward(); rightCut.sendForward(); leftCut.sendForward(); vert.sendForward(); horiz.sendForward(); body.sendForward(); } // standard get and set color needed by Drawable2DInterface public void setColor(Color c) { body.setColor(c); } public Color getColor() { return body.getColor(); } public void moveTo(Location newLoc) { moveTo(newLoc.getX(), newLoc.getY()); } // hiding and showing public boolean isHidden() { return body.isHidden(); } public void show() { border.show(); rightCut.show(); leftCut.show(); vert.show(); horiz.show(); body.show(); } public void hide() { border.hide(); rightCut.hide(); leftCut.hide(); vert.hide(); horiz.hide(); body.hide(); } public DrawingCanvas getCanvas() { return body.getCanvas(); } public void addToCanvas(DrawingCanvas c) { border.addToCanvas(c); rightCut.addToCanvas(c); leftCut.addToCanvas(c); vert.addToCanvas(c); horiz.addToCanvas(c); body.addToCanvas(c); } public void removeFromCanvas() { border.removeFromCanvas(); rightCut.removeFromCanvas(); leftCut.removeFromCanvas(); vert.removeFromCanvas(); horiz.removeFromCanvas(); body.removeFromCanvas(); } }
import objectdraw.*; import java.awt.*; import java.util.Random; /* * A T-shirt object, this one implements the Objectdraw built in * interface Drawable2DInterface. * * Jim Teresco, The College of Saint Rose, Spring 2014 * Based on example from Williams College CSCI 134 * * $Id: TShirt.java 2329 2014-02-27 02:46:26Z terescoj $ */ public class TShirt implements Drawable2DInterface { // constants to define the size of the shirt // note how in this case, all are defined relative // to a single "SIZE" that we can change and // have all components change in an appropriate // proportion. private static final double SIZE = 120; private static final double SLEEVE_WIDTH = SIZE; private static final double SLEEVE_HEIGHT = 0.2*SIZE; private static final double BODY_WIDTH = 0.6*SIZE; private static final double BODY_HEIGHT = (0.65)*SIZE; private static final double BODY_INSET = 0.2*SIZE; private static final double NECK_WIDTH = 0.3*SIZE; private static final double NECK_HEIGHT = 0.06*SIZE; private static final double NECK_INSET = 0.35*SIZE; // rectangles that form a border around the shirt private FramedRect sleeveTrim, bodyTrim; private FramedOval neckTrim; // rectangles that form the interior color of the shirt private FilledRect body, sleeves; private FilledOval neck; // Current color of the shirt private Color hue; // Random number generator used to select next object private Random generator = new Random(); // create a new T-shirt with its upper left corner at (x,y). public TShirt(double x, double y, DrawingCanvas canvas) { // create boundary rectangles sleeveTrim = new FramedRect(x, y + NECK_HEIGHT/2, SLEEVE_WIDTH, SLEEVE_HEIGHT, canvas); bodyTrim = new FramedRect(x + BODY_INSET, y + NECK_HEIGHT/2, BODY_WIDTH, BODY_HEIGHT, canvas); // create interior rectangles sleeves = new FilledRect(x+1, y+NECK_HEIGHT/2+1, SLEEVE_WIDTH-1, SLEEVE_HEIGHT-1, canvas); body = new FilledRect(x+BODY_INSET+1, y+NECK_HEIGHT/2+1, BODY_WIDTH-1, BODY_HEIGHT-1, canvas); // give it a neck hole neck = new FilledOval(x + NECK_INSET, y, NECK_WIDTH, NECK_HEIGHT, canvas); neckTrim = new FramedOval(x + NECK_INSET, y, NECK_WIDTH, NECK_HEIGHT, canvas); // set the interior color setColor(); } // move the t-shirt by specified offsets. public void move(double xOffset, double yOffset) { body.move(xOffset,yOffset); neck.move(xOffset,yOffset); sleeves.move(xOffset,yOffset); bodyTrim.move(xOffset,yOffset); sleeveTrim.move(xOffset,yOffset); neckTrim.move(xOffset,yOffset); } // remove the t-shirt from the canvas. public void removeFromCanvas() { body.removeFromCanvas(); neck.removeFromCanvas(); sleeves.removeFromCanvas(); bodyTrim.removeFromCanvas(); sleeveTrim.removeFromCanvas(); neckTrim.removeFromCanvas(); } // move the t-shirt to a new upper-left coordinate position public void moveTo(double x, double y) { move(x - sleeves.getX(), y - neck.getY()); } // returns true if the t-shirt contains the point; false otherwise public boolean contains(Location pt) { return body.contains(pt) || sleeves.contains(pt) || neck.contains(pt); } // pick a new random color for the shirt private void setColor() { hue = new Color(generator.nextInt(256), generator.nextInt(256), generator.nextInt(256)); body.setColor(hue); sleeves.setColor(hue); neck.setColor(hue); } // we are required by Drawable2DInterface to provide an overlaps method // which just checks if the essential parts overlap the other object public boolean overlaps(Drawable2DInterface other) { return other.overlaps(body) || other.overlaps(sleeves) || other.overlaps(neck); } // getLocation, getX, getY are required by Drawable2DInterface public Location getLocation() { return new Location(sleeves.getX(), neck.getY()); } public double getX() { return sleeves.getX(); } public double getY() { return neck.getY(); } // we also must provide getWidth and getHeight public double getWidth() { return SLEEVE_WIDTH; } public double getHeight() { return body.getY() + body.getHeight() - neck.getY(); } // also stacking order methods public void sendToFront() { sleeveTrim.sendToFront(); bodyTrim.sendToFront(); sleeves.sendToFront(); body.sendToFront(); neck.sendToFront(); neckTrim.sendToFront(); } public void sendToBack() { neckTrim.sendToBack(); neck.sendToBack(); body.sendToBack(); sleeves.sendToBack(); bodyTrim.sendToBack(); sleeveTrim.sendToBack(); } public void sendBackward() { sleeveTrim.sendBackward(); bodyTrim.sendBackward(); sleeves.sendBackward(); body.sendBackward(); neck.sendBackward(); neckTrim.sendBackward(); } public void sendForward() { sleeveTrim.sendForward(); bodyTrim.sendForward(); sleeves.sendForward(); body.sendForward(); neck.sendForward(); neckTrim.sendForward(); } // standard get and set color needed by Drawable2DInterface public void setColor(Color c) { sleeves.setColor(c); body.setColor(c); neck.setColor(c); } public Color getColor() { return sleeves.getColor(); } public void moveTo(Location newLoc) { moveTo(newLoc.getX(), newLoc.getY()); } // hiding and showing public boolean isHidden() { return body.isHidden(); } public void show() { body.show(); sleeves.show(); neck.show(); bodyTrim.show(); neckTrim.show(); sleeveTrim.show(); } public void hide() { body.hide(); sleeves.hide(); neck.hide(); bodyTrim.hide(); neckTrim.hide(); sleeveTrim.hide(); } public DrawingCanvas getCanvas() { return body.getCanvas(); } public void addToCanvas(DrawingCanvas c) { body.addToCanvas(c); sleeves.addToCanvas(c); neck.addToCanvas(c); bodyTrim.addToCanvas(c); neckTrim.addToCanvas(c); sleeveTrim.addToCanvas(c); } }