developer.com - Reference
Click here to support our advertisers
SHOPPING
JOB BANK
CLASSIFIEDS
DIRECTORIES
REFERENCE
Online Library
LEARNING CENTER
JOURNAL
NEWS CENTRAL
DOWNLOADS
COMMUNITY
CALENDAR
ABOUT US
Journal:
Get the weekly email highlights from the most popular journal for developers!
Current issue
developer.com
developerdirect.com
htmlgoodies.com
javagoodies.com
jars.com
intranetjournal.com
javascripts.com
All Categories :
Java
Chapter 25
Using Animation
CONTENTS
Animation Basics
A Simple Animation
A Graphics Animation
Improving Animation Display Qualities
An Updated Graphics Animation
Summary
This chapter completes Part IV, "Window Programming,"
by showing you how to include animation sequences in your window
programs. It identifies the basic elements of implementing an
animation and then describes approaches to improving the quality
of an animation's display by selectively repainting parts of a
window and using the MediaTracker
class to support the loading of the images used in an animation.
When you finish this chapter, you'll be able to include animation
in your window programs.
Animation
Basics
While including animation sequences in your Java programs may
at first appear to be complicated, it is, in fact, rather easy
once you learn the basics. Animations are nothing more than the
rapid display of still images such that the pattern of image display
causes the appearance of movement for the objects contained in
the image. To create an animation, you need to produce the sequence
of objects that are to be displayed and then write a Java program
that will display that sequence at a particular display rate.
For me, the hardest part of developing an animation is producing
the images that are to be displayed. This part requires drawing
skills and is completely separate from Java programming. Don't
fret if you are unable to easily draw these animation sequences.
Chances are that you're better at it than I am. The important
point of this chapter is to learn how to display in the form of
an animation the sequences that you do come up with.
Many animations display their image sequences in a looping fashion.
A looping animation gives the appearance that it is much longer
than it actually is, and it can run indefinitely. Looping animations
also require fewer image frames. If your animation displays 10
to 20 image frames per second and you want it to run for a minute,
then you will need 600 to 1200 images. That's a lot of work for
a one-minute animation. It is much easier to develop a small but
varied looping animation and have it loop several times during
the course of a minute.
The major parameter of an animation, besides the type and quality
of the images it displays, is the number of image frames that
it displays per second. This is typically a fixed number between
5 and 25. The more frames per second that are displayed, the smoother
the animation appears to be. The frames-per-second parameter translates
into a frame delay parameter that is used to determine how long
a program should wait before it displays the next image frame.
This is typically measured in milliseconds. For example, frames-per-second
rates of 5, 10, and 20 translate into frame delays of 200, 100,
and 50 milliseconds.
A common approach to implementing an animation is to create a
program thread that runs in an infinite loop and displays the
frames of the animation sequence one at a time, waiting frame-delay
milliseconds between each frame's display.
A Simple
Animation
In order to get a better understanding of the basics of the animation
process, you can develop a simple, character-based animation.
The source code of the SimpleAnimationApp
program is shown in Listing 25.1.
Listing 25.1. The source code of the SimpleAnimationApp
program.
import java.awt.*;
import jdg.ch20.*;
public class SimpleAnimationApp extends Frame implements Runnable
{
Thread animation;
int frameDelay = 100;
String frames[] = {"*","**","***","****","*****","****","***","**","*"};
int numFrames = frames.length;
int currentFrame = 0;
long lastDisplay = 0;
String menuItems[][] = {{"File","Exit"}};
MyMenuBar menuBar = new MyMenuBar(menuItems);
int screenWidth = 200;
int screenHeight = 200;
public static void main(String args[]) {
SimpleAnimationApp app = new SimpleAnimationApp();
}
public SimpleAnimationApp() {
super("Simple Animation");
setup();
pack();
resize(screenWidth,screenHeight);
show();
animation = new Thread(this);
animation.start();
}
void setup() {
setMenuBar(menuBar);
setFont(new Font("default",Font.BOLD,18));
}
public void paint(Graphics g) {
g.drawString(frames[currentFrame],60,60);
}
public void run() {
do {
long time = System.currentTimeMillis();
if(time - lastDisplay > frameDelay)
{
repaint();
try {
Thread.sleep(frameDelay);
}catch(InterruptedException
ex){
}
++currentFrame;
currentFrame %= numFrames;
lastDisplay = time;
}
} while (true);
}
public boolean handleEvent(Event event) {
if(event.id==Event.WINDOW_DESTROY){
System.exit(0);
return true;
}else if(event.id==Event.ACTION_EVENT){
if(event.target instanceof MenuItem){
String arg = (String)
event.arg;
if("Exit".equals(arg))
{
System.exit(0);
return true;
}
}
}
return false;
}
}
Compile and run SimpleAnimationApp.
Your program's display should look like the one shown in Figure 25.1.
Figure 25.1 : A simple animation.
A string of asterisks is modulated to give the appearance of movement.
While this short animation is by no means in line for any awards,
it does illustrate all the basic elements of more complex and
entertaining animations.
The SimpleAnimationApp class
declares the animation thread,
the frameDelay variable,
the array of frames[] used
to implement the animation's display, the numFrames
variable, the currentFrame
variable, the time of the lastDisplay
of a frame, and the standard menu bar and window size variables.
The setup of the SimpleAnimationApp
program is fairly standard, with the exception of the creation
of the animation thread at
the end of the class constructor and the invocation of the animation
thread's start() method.
The paint() method contains
a single statement that is used to display a string of asterisks
on the console window.
The run() method implements
the animation loop. It checks the current system time and the
time of the last image display to see if it is time to display
a new frame. It uses the currentTimeMillis()
method of the System class
to read the current time in milliseconds. If it is time to display
another frame, the run()
method invokes the repaint()
method to display the current frame and then tries to sleep for
frameDelay milliseconds.
It updates the currentFrame
using modular arithmetic and changes the time of lastDisplay.
The handleEvent() method
performs the standard window event handling covered in Chapters 18
through 24.
A
Graphics Animation
Because the SimpleAnimationApp
program provides all the basic elements required of an animation,
we can easily modify the animation to support graphics. Figures 25.2
through 25.5 provide four stick figures
I drew using the Windows Paint program. These crude figures can
be used to create an animation of a stick figure that attempts
to fly.
Figure 25.2 : stickman1.gif.
Figure 25.3 : stickman2.gif.
Figure 25.4 : stickman3.gif.
Figure 25.5 : stickman4.gif.
You may easily substitute your own figures for the ones used in
this example.
The source code of the GraphicAnimationApp
program is shown in Listing 25.2.
Listing 25.2. The source code of the GraphicAnimationApp
program.
import java.awt.*;
import jdg.ch20.*;
public class GraphicAnimationApp extends Frame implements Runnable
{
Thread animation;
int frameDelay = 100;
Image frames[];
int numFrames;
int currentFrame = 0;
long lastDisplay = 0;
String menuItems[][] = {{"File","Exit"}};
MyMenuBar menuBar = new MyMenuBar(menuItems);
int screenWidth = 400;
int screenHeight = 400;
public static void main(String args[]) {
GraphicAnimationApp app = new GraphicAnimationApp();
}
public GraphicAnimationApp() {
super("Graphic Animation");
setup();
pack();
resize(screenWidth,screenHeight);
show();
animation = new Thread(this);
animation.start();
}
void setup() {
setMenuBar(menuBar);
setFont(new Font("default",Font.BOLD,18));
Toolkit toolkit = getToolkit();
frames = new Image[4];
frames[0] = toolkit.getImage("stickman1.gif");
frames[1] = toolkit.getImage("stickman2.gif");
frames[2] = toolkit.getImage("stickman3.gif");
frames[3] = toolkit.getImage("stickman4.gif");
numFrames = frames.length;
}
public void paint(Graphics g) {
g.drawImage(frames[currentFrame],10,10,this);
}
public void run() {
do {
long time = System.currentTimeMillis();
if(time - lastDisplay > frameDelay)
{
repaint();
try {
Thread.sleep(frameDelay);
}catch(InterruptedException
ex){
}
++currentFrame;
currentFrame %= numFrames;
lastDisplay = time;
}
} while (true);
}
public boolean handleEvent(Event event) {
if(event.id==Event.WINDOW_DESTROY){
System.exit(0);
return true;
}else if(event.id==Event.ACTION_EVENT){
if(event.target instanceof MenuItem){
String arg = (String) event.arg;
if("Exit".equals(arg)) {
System.exit(0);
return true;
}
}
}
return false;
}
}
When you run GraphicAnimationApp,
your display should look like the one shown in Figure 25.6.
Figure 25.6 : The GraphicAnimationApp program display.
Unless you have a really fast computer and video card, your program
display probably has some very noticeable flickering. Don't worry
about that problem now. You'll learn ways to improve the quality
of an animation's display in the following section. For now, just
focus on how we modified the SimpleAnimationApp
program to support graphics-based animation.
The GraphicAnimationApp program
is very similar to the SimpleAnimationApp
program. These are the differences between the two programs:
In GraphicAnimationApp,
the frames[] array was changed
from an array of String objects
to an array of Image objects.
In GraphicAnimationApp,
the setup() method was updated
to create a Toolkit object
and use it to load the stickman images.
These simple changes were all that was needed to convert the program
from a simple text-based animation to a graphics-based animation.
Improving
Animation Display Qualities
The GraphicAnimationApp program
has some serious deficiencies in the way that it displays the
animation images. The first and probably the most noticeable problem
is that it tries to start displaying the images before they are
completely loaded. This is an easy problem to solve using the
MediaTracker class.
The MediaTracker class provides
the capability to manage the loading of image files. You use the
addImage() method to add
an image to the list of images being tracked. After adding an
image to a MediaTracker object,
you can then check on the image or all images managed by MediaTracker
object using the access methods provided by the MediaTracker
class.
The other major problem with the animation's display is that the
entire screen is repainted with each new frame, which causes a
significant amount of flickering. This image flickering can be
mitigated by limiting the area of the window that is updated with
each new image. The repaint()
and update() methods of the
component class provide this capability.
You are already familiar with limited screen repainting from using
the repaint() method in Chapter 23,
"The Canvas." The update()
method provides the capability to update a Graphics
object without first clearing the current image. This allows successive
images to be displayed as marginal increments to the currently
displayed image.
Another option to improving an animation's display quality is
to change the frame delay. By decreasing the number of frames
per second being displayed, you are able to lower the rate at
which flickering occurs. However, you do this at the expense of
the overall quality of your animation because higher frame-display
rates tend to smooth out any gaps between successive images.
An
Updated Graphics Animation
The GraphicUpdateApp program
shows how to use the MediaTracker
class, together with limited repainting and frame-delay adjustments,
to improve the quality of the GraphicAnimationApp
program. Its source code is shown in Listing 25.3.
Listing 25.3. The source code of the GraphicUpdateApp
program.
import java.awt.*;
import jdg.ch20.*;
public class GraphicUpdateApp extends Frame implements Runnable
{
Thread animation;
int frameDelay = 200;
Image frames[];
int numFrames;
int currentFrame = 0;
long lastDisplay = 0;
boolean fullDisplay = false;
MediaTracker tracker;
String menuItems[][] = {{"File","Exit"}};
MyMenuBar menuBar = new MyMenuBar(menuItems);
int screenWidth = 400;
int screenHeight = 400;
public static void main(String args[]) {
GraphicUpdateApp app = new GraphicUpdateApp();
}
public GraphicUpdateApp() {
super("Updated Graphic Animation");
setup();
pack();
resize(screenWidth,screenHeight);
show();
animation = new Thread(this);
animation.start();
}
void setup() {
setMenuBar(menuBar);
setFont(new Font("default",Font.BOLD,18));
Toolkit toolkit = getToolkit();
frames = new Image[4];
frames[0] = toolkit.getImage("stickman1.gif");
frames[1] = toolkit.getImage("stickman2.gif");
frames[2] = toolkit.getImage("stickman3.gif");
frames[3] = toolkit.getImage("stickman4.gif");
numFrames = frames.length;
tracker = new MediaTracker(this);
for(int i=0;i<numFrames;++i) tracker.addImage(frames[i],i);
}
public void paint(Graphics g) {
if(allLoaded())
g.drawImage(frames[currentFrame],10,10,this);
else{
String stars = "*";
for(int i=0;i<currentFrame;++i)
stars += "*";
g.drawString(stars,60,60);
}
}
boolean allLoaded() {
for(int i=0;i<numFrames;++i) {
if(tracker.statusID(i,true) != MediaTracker.COMPLETE)
return false;
}
return true;
}
public void run() {
do {
long time = System.currentTimeMillis();
if(time - lastDisplay > frameDelay)
{
if(allLoaded()) {
if(fullDisplay) repaint(10,90,160,78);
else{
fullDisplay
= true;
repaint();
}
}else repaint();
try {
Thread.sleep(frameDelay);
}catch(InterruptedException
ex){
}
++currentFrame;
currentFrame %= numFrames;
lastDisplay = time;
}
} while (true);
}
public boolean handleEvent(Event event) {
if(event.id==Event.WINDOW_DESTROY){
System.exit(0);
return true;
}else if(event.id==Event.ACTION_EVENT){
if(event.target instanceof MenuItem){
String arg = (String) event.arg;
if("Exit".equals(arg))
{
System.exit(0);
return true;
}
}
}
return false;
}
}
When you run GraphicUpdateApp,
it displays an animated string of asterisks while the image files
are being loaded. After that, it will immediately display the
image animation. This reduces the unsightly flickering caused
when an image is displayed while it is being loaded.
Notice how GraphicUpdateApp
implements the limited-area repainting. You can run your mouse
over the image display to determine the boundaries of the repaint
area.
You should also notice that GraphicUpdateApp
displays images at a slower rate. The frame- delay rate was increased
from 100 microseconds to 200 microseconds, decreasing the frame
display rate by a factor of 2.
The changes made to GraphicAnimationApp
by GraphicUpdateApp consist
of the declaration of the fullDisplay
and tracker variables and
modifications to the setup(),
paint(), and run()
methods. In addition, the allLoaded()
method was created:
The fullDisplay
variable is used to ensure that a full display of the stickman
is accomplished before attempting a limited display using the
repaint() method. The tracker
variable is used to refer to a MediaTracker
object.
The setup()
method is updated to create the MediaTracker
object and to add the images being loaded with this object.
The paint()
method is updated to draw the images after they've been loaded
and to draw asterisk strings before the images are loaded.
The allLoaded()
method uses the statusID()
method of the MediaTracker
class to determine whether all images have been completely loaded.
The run()
method has been modified to use the allLoaded()
method and the fullDisplay
variable to determine whether it should repaint the entire screen
or only a limited portion of it.
Summary
This chapter shows how to include animation sequences in your
window programs. It identifies the basic elements of implementing
an animation and describes approaches to improving the quality
of an animation's display. It shows you how to selectively repaint
parts of a window and how to use the MediaTracker
class to support the loading of the images used in an animation.
Chapter 26, "Client Programs,"
begins Part V, "Network Programming."
Contact
reference@developer.com with questions or comments.
Copyright 1998
EarthWeb Inc., All rights reserved.
PLEASE READ THE ACCEPTABLE USAGE STATEMENT.
Copyright 1998 Macmillan Computer Publishing. All rights reserved.
Wyszukiwarka
Podobne podstrony:
ch25ch25 (4)ch25 (9)CH25 (11)ch25ch25ch25 (2)ch25ch25 (10)ch25ch25ch25ch25ch25ch25ch25ch25 (5)więcej podobnych podstron