Computer Science 252
Problem Solving with Java
Fall 2015, 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.
*
* $Id: ItemGenerator.java 2566 2015-03-05 05:07:26Z terescoj $
*
* @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;
// delay between items -- half second
private static final int DELAY_FOR = 500;
// 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(DELAY_FOR); // 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);
}
}