Hire a senior Perl / Python programmer today; download my up-to-date resume (PDF)
John Bokma Java
freelance Perl programmer

Animation

version: 1.3 (11-September-1997) | 2 comments

The following article was written back in 1997. I have put it back on line for historical reasons. It probably is quite outdated. You might want to call the paint() method from the update() method instead of vice versa as described below. Note that I have slightly edited the code to reflect my current notation preferences (mainly the placing of the opening curly brace).

This document describes how to implement an applet for displaying an animation. It assumes that you already understand some of the basics of Java-programming.

An offscreen buffer (double-buffering) is used to prevent flickering of the animation.

A skeleton of an applet is given below and the details are given step by step.

import java.awt.*;
import java.applet.Applet;

public class AppletName extends Applet implements Runnable {

    // member variables

    // methods
}

Name the source file AppletName.java. Replace AppletName with the name of your applet.

The methods which must be overriden can be grouped into three categories:

This document concludes with the source of a small example.

Initialization

The init method is used to create the offscreen buffer. Add the following two static member variables to your applet:

final static int WIDTH  = 200;
final static int HEIGHT = 180;

These contain the width and height of your applet. You can change the values to the size you require. The two variables are final and static because in this case they are constants defined inside the applet.

The offscreen buffer consists of an image and a graphics context, so add the following two member variable definitions:

Image    image;
Graphics graphics;

Now the offscreen buffer can be created in the init method of the applet:

public void init() {

    image    = createImage( WIDTH, HEIGHT );
    graphics = image.getGraphics();

    // your initialisation
}

The init method is called just once in an applet's lifetime.

Starting and stopping the animation thread

A thread is used to start the animation when the user is watching the applet and stop it when the user has moved to a different page. The start and stop methods can be called more than once in an applet's lifetime.

Add the following member variable definition:

Thread runner = null;

The start method is used to create the thread. This method is called each time the user visits your page.

public void start() {

    if ( runner == null ) {

        runner = new Thread( this );
        runner.start();
    }
}

The stop method stops the thread when the user leaves the page.

public void stop() {

     if ( runner != null && runner.isAlive() )
         runner.stop();

    runner = null;
}

Painting the animation

The animation must be updated regularly, so let the thread sleep a number of milliseconds after drawing the animation. In this example the value of 20 (milliseconds) is used.

public void run() {

    while ( runner != null ) {

        repaint();

        try {

            Thread.sleep(20);

        } catch ( InterruptedException e ) {

            // do nothing

        }
    }
}

The actual painting of the animation takes place inside the update method. So the paint method consist of just the call to the update method, i.e.

public void paint(Graphics g) {

    update(g);
}

Use the offscreen buffer to draw the animation, i.e. use graphics.someMethod instead of g.someMethod. The offscreen buffer must first be set to the background of your animation. This can be just a plane color or an image. In the first case you can use the fillRect method, e.g.

graphics.setColor( Color.white );           // white background
graphics.fillRect( 0, 0, WIDTH, HEIGHT );   // draw it

And in the latter, you can use the drawImage method, e.g.

graphics.drawImage(yourImage, 0, 0, this);

Remember that (0, 0) is the top left of the applet.

After drawing the background, you can start drawing the animation.

The final statement of the update method copies the offscreen buffer to the screen.

public void update( Graphics g ) {

    // draw the background of your animation

    // use graphics to draw the animation

    g.drawImage(image, 0, 0, this);
}

Animation example

After compiling this example (i.e. javac BouncingLines.java) you can embed it into a HTML page as follows:

<APPLET CODE="BouncingLines.class" WIDTH=200 HEIGHT=100
>
Please use a Java-enabled browser.
</APPLET>

Use the same WIDTH and HEIGHT values as in the source.

BouncingLines.java

import java.awt.*;
import java.applet.Applet;

public class BouncingLines extends Applet implements Runnable {

    Thread runner = null;

    final static int WIDTH  = 200;
    final static int HEIGHT = 100;

    Image    image;
    Graphics graphics;

    // bouncing lines member variables

    int[] x1;
    int[] y1;
    int[] x2;
    int[] y2;

    int dx1 = 2 + (int)( 3 * Math.random() );
    int dy1 = 2 + (int)( 3 * Math.random() );
    int dx2 = 2 + (int)( 3 * Math.random() );
    int dy2 = 2 + (int)( 3 * Math.random() );

    static int first = 0;

    final static int LINES = 50;


    public void init() {

        // create arrays to hold the line coordinates

        x1 = new int[LINES];
        y1 = new int[LINES];
        x2 = new int[LINES];
        y2 = new int[LINES];

        // initialise the first line

        x1[0] = (int)( WIDTH  * Math.random() );
        y1[0] = (int)( HEIGHT * Math.random() );
        x2[0] = (int)( WIDTH  * Math.random() );
        y2[0] = (int)( HEIGHT * Math.random() );

        // initialise all the other lines

        for ( int i = 1; i < LINES; i++ ) {

            x1[i] = x1[0];
            y1[i] = y1[0];
            x2[i] = x2[0];
            y2[i] = y2[0];
        }
        image    = createImage( WIDTH, HEIGHT );
        graphics = image.getGraphics();
    }


    public void start() {

        // user visits the page, create a new thread

        if ( runner == null ) {

            runner = new Thread( this );
            runner.start();
        }
    }


    public void stop() {

        // user leaves the page, stop the thread

        if ( runner != null && runner.isAlive() )
            runner.stop();

        runner = null;
    }


    public void run() {

        while (runner != null) {

            repaint();

            try {

                Thread.sleep( 20 );

            } catch ( InterruptedException e ) {

                // do nothing
            }
        }
    }


    public void paint( Graphics g ) {

        update( g );
    }


    public void update( Graphics g ) {

        // clear the background to white

        graphics.setColor( Color.white );
        graphics.fillRect( 0, 0, WIDTH, HEIGHT );

        // draw the lines

        graphics.setColor( Color.red );

        int line = first;

        for ( int i = 0; i < LINES; i++ ) {

            graphics.drawLine( x1[line], y1[line],
                               x2[line], y2[line] );
            line++;
            if ( line == LINES ) line = 0;
        }

        line = first;

        first--;

        if ( first < 0 ) first = LINES - 1;

        x1[first] = x1[line];
        y1[first] = y1[line];
        x2[first] = x2[line];
        y2[first] = y2[line];

        // move the "first" line

        if (x1[first] + dx2 < WIDTH)
            x1[first] += dx1;
        else
            dx1 = -(2 + (int)( 3 * Math.random() ));

        if (x1[first] + dx1 >= 0)
            x1[first] += dx1;
        else
            dx1 = 2 + (int)( 3 * Math.random() );

        if (y1[first] + dy1 < HEIGHT)
            y1[first] += dy1;
        else
            dy1 = -(2 + (int)( 3 * Math.random() ));

        if (y1[first] + dy1 >= 0)
            y1[first] += dy1;
        else
            dy1 = 2 + (int)( 3 * Math.random() );

        if (x2[first] + dx2 < WIDTH)
            x2[first] += dx2;
        else
            dx2 = -(2 + (int)( 3 * Math.random() ));

        if (x2[first] + dx2 >= 0)
            x2[first] += dx2;
        else
            dx2 = 2 + (int)( 3 * Math.random() );

        if (y2[first] + dy2 < HEIGHT)
            y2[first] += dy2;
        else
            dy2 = -(2 + (int)( 3 * Math.random() ));

        if (y2[first] + dy2 >= 0)
            y2[first] += dy2;
        else
            dy2 = 2 + (int)( 3 * Math.random() );

        // copy buffer to screen

        g.drawImage( image, 0, 0, this );
    }
}

Examples of Java applets using animation

Please post a comment | read 2 comments, latest by das Keks | RSS feed