The general principles for producing animated images on your screen are the same as for a film. You display, or draw, a series of static images on the screen with a fixed interval of time between one image and the next. Each image differs slightly from its predecessor so that an object that is in a different position on successive images will appear to move. Since you know how to display one image you are part way there, and since you also know how to create a loop it is clearly not going to be too difficult to implement animated images.
There are two basic ways in which animation can be generated. You can create or obtain a set of images that are snapshots of the position of everything at fixed intervals, and then display them in sequence. Alternatively you can create or obtain an image of whatever you want to have moving, and display it at different positions at fixed intervals of time. Of course, before you display the moving entity at any given position, you must erase it at whatever position it was previously. Come to think of it, you already know one way to do this. Drawing a line or a circle in Sketcher produces an animated effect while you drag the mouse cursor.
Animation is often used in applets to make web pages more interesting and eye catching and there can be multiple, independent animated images in a page. The code producing an animated effect generally runs continuously, so you usually have to make this independent of any other code that may be running to allow the apparent concurrent operations. For this reason, you always implement code that generates an animated effect as a separate thread. If you don't implement your animation in a separate thread, it is unlikely to work properly, and other code that you expect to be executable while the animation is running will not work either. This goes for animations in applications as well as applets. We have already discussed threads in some detail so we just need to dredge the stuff up again and apply it for drawing images.
An Animated Applet
Just so that you know where we are heading, our first program illustrating animation will be an applet that drops the Wrox logo from a great height to see what happens. Since Wrox Press is an immensely resilient company, the logo will bounce.
To implement this we just need to draw the logo at its new position at fixed intervals of time - the new position being determined by how far the logo has fallen during the time interval. We can store the coordinates of the current location of the image in data members of the applet class, imageX and imageY and the paint() method of the inner class ImagePanel will draw the image at that position. The animation code in the run() method will need access to the height of the image so it can work out when the image hits the ground, so we should store the image dimensions, imageWidth and imageHeight, as data members too.
We will call the applet class LogoBounce, so the outline contents of the source file will be:
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.net.*;
public class LogoBounce extends JApplet
implements Runnable
{
// This method is called when the applet is loaded
public void init()
{
// Code to initialize the applet...
}
// This method is called when the browser starts the applet
public void start()
{
bouncer = new Thread(this); // Create animation thread
bouncing = true;
bouncer.start(); // and start it
}
// This method is called when the browser wants to stop the applet
// - when is it not visible for example
public void stop()
{
bouncing = false; // Stop the animation loop
bouncer = null; // Discard the thread
}
// This method is called when the animation thread is started
public void run()
{
// Code for the animation thread...
}
class ImagePanel extends JPanel
{
public ImagePanel(Image image)
{
this.image = image;
}
public void paint(Graphics g)
{
// Initialize the animation...
while(bouncing)
{
// Code for the animation loop
}
}
Image image; // The image
}
Thread bouncer; // The animation thread
boolean bouncing = false; // Controls animation thread
ImagePanel imagePanel; // Panel for the image
int imageWidth, imageHeight; // Image dimensions
int imageX, imageY; // Current image position
}
All the basic things we need are here. In the init() method we will set up a component on which we can draw an image and add this to the content pane for the applet, just as we did in the previous example. The start() method creates the animation thread, bouncer, sets the variable, bouncing, that will control the animation loop to true, and starts the thread. The run() method will contain the animation loop that will continue to run as long as bouncing is true. In the stop() method we just set bouncing to false to stop the animation loop in the run() method, then discard the animation thread object by setting bouncer to null. The start() method will create a new thread if the animation needs to be restarted.
We will fetch the image from the file in the init() method using the getImage() method as we did in the previous example. There's a complication here though. The browser will call start() as soon as the init() method returns to start the applet, and this will start the thread to do the animation. Since this will involve calculations involving the height of the image, we don't want this to go ahead until we are sure the height is available. One way of determining when an image has been loaded is to make use of something called a media tracker.
Continued...