Computer Science 252
Problem Solving with Java

Fall 2015, The College of Saint Rose

BigSnowman Demo

A working demo of BigSnowman will appear below. Click inside the applet to interact with it.



BigSnowman BlueJ Project

Click here to download a BlueJ project for BigSnowman.


BigSnowman Source Code

The Java source code for BigSnowman is below. Click on a file name to download it.


BigSnowman.java

import objectdraw.*;
import java.awt.*;

/*
 * Example BigSnowman: a recursive object to create a many-leveled
 * snowman-like object.  Its base snowball is determined by
 * the point and diameter passed to the constructor, and successive
 * smaller snowballs are placed atop that one until they become too small
 *
 * Jim Teresco, The College of Saint Rose, CSC 252, Spring 2014
 *
 * $Id: BigSnowman.java 2333 2014-03-12 17:48:14Z terescoj $
 */

public class BigSnowman {

    // the minimum size of a snowball to be added as the "head"
    private static final double MIN_HEAD_SIZE = 25;
    
    // scaling factor for each smaller snowball
    private static final double SCALE_FACTOR = 0.7;
    
    // the slightly blue colors for the interior and borders of snowballs
    private static final Color SNOW_COLOR = new Color(240, 250, 255);
    private static final Color BORDER_COLOR = new Color(200, 200, 255);
    
    // our instance variables to represent the snowman
    // the 2 components that make up the base snowball
    private FilledOval base;
    private FramedOval baseFrame;
    
    // and an instance variable to keep track of any additional snowballs
    private BigSnowman rest;
    
    // construct one
    public BigSnowman(Location upperLeft, double diameter, DrawingCanvas canvas) {
        
        // The base is easy: Just construct our two graphical components
        base = new FilledOval(upperLeft, diameter, diameter, canvas);
        base.setColor(SNOW_COLOR);
        baseFrame = new FramedOval(upperLeft, diameter, diameter, canvas);
        baseFrame.setColor(BORDER_COLOR);
        
        // how big would the next snowball up be?
        double newDiameter = diameter * SCALE_FACTOR;
        // now, we construct the rest if it would be large enough to be displayed
        if (newDiameter >= MIN_HEAD_SIZE) {
            // how much to move right to center next snowball on this one?
            double xOffset = (diameter - newDiameter)/2;
            upperLeft.translate(xOffset, -newDiameter);
            rest = new BigSnowman(upperLeft, newDiameter, canvas);
        }
    }
    
    // we'll need contains and move to support dragging
    public boolean contains(Location point) {
        
        if (base.contains(point)) return true;
        
        if (rest != null) return rest.contains(point);
        
        return false;
   
    }
    
    public void move(double dx, double dy) {
        
        // move the pieces we're responsible for
        base.move(dx, dy);
        baseFrame.move(dx, dy);
        
        // and if there's more, move those recursively
        if (rest != null) {
            rest.move(dx, dy);
        }
    }
}

BigSnowmanController.java

import objectdraw.*;
import java.awt.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/*
 * Example BigSnowman: the window controller to make many-leveled
 * snowman-like objects on the canvas.
 * 
 * The game: 
 * - Press the mouse to create a new snowman whose base size
 * is determined by the JSlider
 * - Press on most recent snowman to drag him instead of creating
 * a new snowman
 *
 * Jim Teresco, The College of Saint Rose, CSC 252, Spring 2014
 *
 * $Id: BigSnowmanController.java 2333 2014-03-12 17:48:14Z terescoj $
 */

public class BigSnowmanController extends WindowController 
    implements ChangeListener {

    // keep track of the newest snowman
    private BigSnowman newestSnowman;
    
    // valid range of snowman base sizes
    private static final int MIN_SIZE = 35;
    private static final int MAX_SIZE = 200;
    
    // our Swing components: a slider and label for current selected size
    private JLabel sizeDisplay;
    private JSlider sizer;
    
    // standard dragging code
    private boolean dragging;
    private Location lastMouse;
    
    // set up GUI
    public void begin() {
        
        // Swing setup
        Container contentPane = getContentPane();
        
        // we'll put our slider and label up north
        JPanel northPanel = new JPanel();
        
        // label and slider into the panel
        sizeDisplay = new JLabel("" + MIN_SIZE);
        northPanel.add(sizeDisplay);
        
        sizer = new JSlider(JSlider.HORIZONTAL, MIN_SIZE, MAX_SIZE, MIN_SIZE);
        northPanel.add(sizer);
        
        // put our panel in the north
        contentPane.add(northPanel, BorderLayout.NORTH);
        
        // and we'll listen for slider changes so we can update the label
        sizer.addChangeListener(this);
        
        contentPane.validate();
    }
    
    public void onMousePress(Location point) {
    
        // drag if we've pressed on the newest snowman
        if (newestSnowman != null && newestSnowman.contains(point)) {
            dragging = true;
            lastMouse = point;
        }
        // create a new one otherwise
        else {
            newestSnowman = new BigSnowman(point, sizer.getValue(), canvas);
            dragging = false;
        }
    }

    public void onMouseDrag(Location point) {
    
        if (dragging) {
            newestSnowman.move(point.getX() - lastMouse.getX(),
                               point.getY() - lastMouse.getY());
            lastMouse = point;
        }
    }
    
    public void onMouseRelease(Location point) {
    
        if (dragging) {
            newestSnowman.move(point.getX() - lastMouse.getX(),
                               point.getY() - lastMouse.getY());
            lastMouse = point;
        }
    }
       
    // our change listener
    public void stateChanged(ChangeEvent e) {
    
        sizeDisplay.setText("" + sizer.getValue());
    }
    
}