CrashingTrain


Your browser is ignoring the <APPLET> tag!

This program draws a train sitting on tracks when the program starts. When the user tries to drag the train, it crashes with a NullPointerException. The problem is that the car is declared twice, once as an instance variable and once as a variable local to the constructor. The constructor sets the local variable. When the contains method is called, it tries to use the instance variable, but that variable has not been set.

Please refer to the MovingTrain example from the previous class for the correct way to do this.

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

/**
    Demonstrates the variety of graphical constructs available in objectdraw
    by drawing a picture using the shapes.
    
    @author Barbara Lerner
*/
public class MovingTrain extends WindowController
{
    // The train in the drawing
    private Train train;
    
    // The background
    private FilledRect sky;
    private FilledRect grass;
    
    // Remember which object is being dragged, if either
    private boolean trainGrabbed;
    // Location where last drag started
    private Location lastPoint;
    
    // Colors for the background
    private static final Color GRASS_COLOR = Color.GREEN;
    private static final Color DARK_GRASS = GRASS_COLOR.darker();
    private static final Color SKY_COLOR = Color.BLUE;
    private static final Color DARK_SKY = SKY_COLOR.darker();
    
    // Size of the window
    private static final int WINDOW_WIDTH = 600;
    private static final int WINDOW_HEIGHT = 400;
    
    // Location of grass
    private static final int GRASS_TOP = WINDOW_HEIGHT * 5 / 8;
    
    // Train location
    private static final int TRAIN_LEFT = 50;
    private static final int TRACK_HEIGHT = WINDOW_HEIGHT * 7 / 8;
    
    /**
     * Draws a train of a fixed size at a fixed location when the program starts.
     */
    public void begin () {
        // Set the size of the window that we want to have.  Note that the height includes
        // the height of the menu bar above the drawing area.  Therefore the drawing area will
        // be slightly smaller than what we specify.
        resize (WINDOW_WIDTH, WINDOW_HEIGHT);

        // grass
        grass = new FilledRect (0, GRASS_TOP, getWidth(), getHeight() - GRASS_TOP, canvas);
        grass.setColor (GRASS_COLOR);
        
        // sky
        sky = new FilledRect (0, 0, getWidth(), GRASS_TOP, canvas);
        sky.setColor (SKY_COLOR);
        
        // The complex objects in the scene
        train = new Train (TRAIN_LEFT, TRACK_HEIGHT, canvas);
        
        // This is the train track that the car sits on.  The parameters for a line are:
        //     x coordinate of first end point
        //     y coordinate of first end point
        //     x coordinate of second end point
        //     y coordinate of second end point
        //     canvas
        // In this case, we need to be careful to pick coordinates that will draw
        // a horizontal line directly beneath the train's wheels.  We also want to be 
        // sure the line stretches the entire width of the window.
        new Line (0, TRACK_HEIGHT, getWidth(), TRACK_HEIGHT, canvas);
     }
    
     /**
      * On each mouse click produce a puff of smoke.
      * @param point where the user clicked.
      */
     public void onMouseClick (Location point) {
         train.produceSmoke();
     }
     
     /**
      * Begin a drag if the user presses the mouse button over the train or cloud
      * @param point where the user pressed the mouse button down
      */
     public void onMousePress (Location point) {
         // Prepare to drag the train
         if (train.contains (point)) {
             trainGrabbed = true;
             lastPoint = point;
         }
     }
     
     /**
      * Drag the train or cloud if either were selected
      * @param point where the mouse is at the end of the drag
      */
     public void onMouseDrag (Location point) {
         // Drag the train
         if (trainGrabbed) {
             // The train only moves horizontally, so ignore how far the mouse moved vertically
            double dx = point.getX() - lastPoint.getX();
            train.move (dx);
            lastPoint = point;
        }
    }
    
    /**
     * End the drag
     * @param point where the mouse is when the button is released
     */
    public void onMouseRelease (Location point) {
        trainGrabbed = false;
    }

}

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

/**
    A train consisting of multiple shapes.  The train can move and change
    color.
    
    @author Barbara Lerner
*/
public class Train 
{
    // Locations and sizes of parts of the train
    private static final int CAR_HEIGHT = 100;
    private static final int CAR_WIDTH = 300;
    private static final int WHEEL_SIZE = CAR_HEIGHT / 2;
    private static final int SMOKESTACK_HEIGHT = CAR_HEIGHT / 2;
    private static final int SMOKESTACK_WIDTH = CAR_WIDTH / 6;
    private static final int SMOKE_HEIGHT = SMOKESTACK_HEIGHT;
    private static final int SMOKE_WIDTH = SMOKESTACK_WIDTH / 2;
    
    // Distance train moves as on each step
    private static final int MOVE_AMOUNT = CAR_WIDTH / 10;
    
    // Colors of the train parts
    private static final Color CAR_COLOR = Color.RED;
    private static final Color DARK_CAR = CAR_COLOR.darker();
    private static final Color WHEEL_COLOR = Color.BLACK;
    private static final Color DARK_WHEEL = WHEEL_COLOR.darker();
    private static final Color SMOKESTACK_COLOR = Color.DARK_GRAY;
    private static final Color DARK_SMOKESTACK = SMOKESTACK_COLOR.darker();
    private static final Color SMOKE_COLOR = new Color (230, 230, 230);
    private static final Color DARK_SMOKE = SMOKE_COLOR.darker();
    
    // The parts of the train
    private FilledRect car;
    private FilledOval backWheel;
    private FilledOval frontWheel;
    private FilledRect smokestack;
        
    // Portion of screen to draw in
    private DrawingCanvas trainCanvas;
    
    /**
     * Draws a train.
     * @param left the back of the train car
     * @param trackHeight height of the train track the car sits on
     * @param canvas where to draw
     */
    public Train (double left, double trackHeight, DrawingCanvas canvas) {
        FilledRect car = new FilledRect(left, trackHeight - CAR_HEIGHT - WHEEL_SIZE, CAR_WIDTH, CAR_HEIGHT, canvas);
        car.setColor(CAR_COLOR);
        backWheel = new FilledOval (left + WHEEL_SIZE, trackHeight - WHEEL_SIZE, WHEEL_SIZE, WHEEL_SIZE, canvas);
        backWheel.setColor (WHEEL_COLOR);
        frontWheel = new FilledOval (left + CAR_WIDTH - 2 * WHEEL_SIZE, trackHeight - WHEEL_SIZE, WHEEL_SIZE, WHEEL_SIZE, canvas);
        frontWheel.setColor (WHEEL_COLOR);
        smokestack = new FilledRect (left + CAR_WIDTH - 2 * SMOKESTACK_WIDTH, car.getY() - SMOKESTACK_HEIGHT, SMOKESTACK_WIDTH, SMOKESTACK_HEIGHT, canvas);
        smokestack.setColor (SMOKESTACK_COLOR);
        trainCanvas = canvas;
     }
     
     /**
      * @return true if point is on the train.  The smoke does not count as part of the train.
      * @param point the location to check for containment
      */
     public boolean contains (Location point) {
         if (car.contains (point)) {
             return true;
         }
         else if (backWheel.contains (point)) {
             return true;
         }
         else if (frontWheel.contains (point)) {
             return true;
         }
         else if (smokestack.contains (point)) {
             return true;
         }
         
         // The point is not in any of the parts of the train
         return false;
     }
     
     /**
      * Move the train relative to its current location
      * @param dx the distance to move right
      * @param dy the distance to move down
      */
     public void move (double dx) {
         car.move (dx, 0);
         backWheel.move (dx, 0);
         frontWheel.move (dx, 0);
         smokestack.move (dx, 0);
     }

     public FilledOval produceSmoke () {
         FilledOval smoke = new FilledOval (smokestack.getX() + (SMOKESTACK_WIDTH - SMOKE_WIDTH) / 2, 
            smokestack.getY() - 1.5 * SMOKE_HEIGHT, SMOKE_WIDTH, SMOKE_HEIGHT, trainCanvas);
         smoke.setColor(SMOKE_COLOR);
         return smoke;
     }
             
}