Previous | Next | Trail Map | Creating a GUI with JFC/Swing | Working with Graphics

Moving an Image Across the Screen

This page features an example applet that moves one image (a rocketship) in front of a background image (a field of stars). You could implement this in one of two ways -- either using one label per image, or using one custom component that paints both images. Because this lesson features painting, this section features the custom component approach, as implemented in MovingImageTimer.java.

Note: You can also see an alternate implementation, which uses labels and a layered pane. You can find it in MovingLabels.java, which you can run by visiting MovingLabels.html.

Below are the two images this applet uses.

rocketship.gif:

starfield.gif:

Here's a picture of the applet's GUI. Remember that you can click on the applet to stop or start the animation.

Click this figure to run the applet.
This is a picture of the applet's GUI. To run the applet, click the picture. The applet will appear in a new browser window.

Note: The rocketship image has a transparent background. The transparent background makes the rocketship image appear to have a rocketship shape, no matter what color background it's painted on top of. If the rocketship background weren't transparent, then instead of the illusion of a rocketship moving through space, you'd see a rocketship on top of a rectangle moving through space.

The code for performing this animation isn't complex. Essentially, it's the applet animation template plus a few additional lines of code. The additional code loads the images, paints the background image, and then uses a simple algorithm to determine where to paint the moving image. Here is the new code: [PENDING: update this]

...//Where the GUI is constructed:
[PENDING: put getImage calls here]

...//In the paintComponent method:
    super.paintComponent(g); //paint any space not covered
                             //by the background image
    int compWidth = getWidth();
    int compHeight = getHeight();

    //If we have a valid width and height for the
    //background image, paint it.
    imageWidth = background.getWidth(this);
    imageHeight = background.getHeight(this);
    if ((imageWidth > 0) && (imageHeight > 0)) {
        g.drawImage(background,
                    (compWidth - imageWidth)/2,
                    (compHeight - imageHeight)/2, this);
    }

    //If we have a valid width and height for the
    //foreground image, paint it.
    imageWidth = foreground.getWidth(this);
    imageHeight = foreground.getHeight(this);
    if ((imageWidth > 0) && (imageHeight > 0)) {
        g.drawImage(foreground,
                    ((frameNumber*5)
                      % (imageWidth + compWidth))
                      - imageWidth,
                    (compHeight - imageHeight)/2,
                    this);
    }
}
You might think that this program doesn't need to clear the background, since it uses a background image. However, clearing the background is still necessary. One reason is that the applet usually starts painting before the images are fully loaded. If the rocketship image loaded before the background image, you would see parts of multiple rocketship until the background image loaded. Another reason is that if the applet painting area were wider than the background image, for some reason, then you'd see multiple rocketships to either side of the background image.

You could solve the first problem by delaying all painting until both images are fully loaded. The second problem could be solved by scaling the background image to fit the entire applet area. You'll learn how to wait for images to be fully loaded in Improving the Appearance and Performance of Image Animation, later in this lesson. Scaling is described in Displaying Images.


Previous | Next | Trail Map | Creating a GUI with JFC/Swing | Working with Graphics