Fun with Java: Frame Animation

Preface

Having fun with Java

This is one of the lessons in a miniseries that will concentrate on
having fun while programming in Java.

This miniseries will include a variety of Java programming topics that
fall in the category of fun programming. This particular lesson
is the eighth in of a group of lessons that will teach you how to write
animation programs in Java.

The first lesson in the group was entitled
Fun
with Java: Sprite Animation, Part 1. That lesson, plus the six
lessons following that one, provided an in-depth explanation of the use
of Java for doing sprite animation.

Related Articles

What is the difference between sprite animation and frame animation?
This is how I view the difference between the two.

With sprite animation, an image moves around on the computer screen,
but the look of that image doesn't change over time.

With frame animation, the look of an image can change over time, whether
it moves or not.

Spherical sea creatures

In this program, I will combine the two such that spherical sea creatures
will swim around in a fish tank. Each creature will change the way
it looks over time. In particular, each creature will change its
color as it swims.

Viewing tip

You may find it useful to open another copy of this lesson in a separate
browser window. That will make it easier for you to scroll back and
forth among the different figures and listings while you are reading about
them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection
of online Java tutorials. You will find those lessons published at
Gamelan.com.
However, as of the date of this writing, Gamelan doesn't maintain a consolidated
index of my Java tutorial lessons, and sometimes they are difficult to
locate there. You will find a consolidated index at
Baldwin's
Java Programming Tutorials.

Preview

Animation in Java

This is one of a group of lessons that will teach
you how to write animation programs in Java. These lessons will teach
you how to write sprite animation, frame animation, and a combination of
the two.

Spherical sea creatures

The first program, which was discussed in the
previous seven lessons, showed you how to use sprite animation to cause
a group of colored spherical sea creatures to swim around in a fish tank.
A screen shot of the output produced by that program is shown in Figure
1.

Figure 1. Animated spherical sea creatures
in a fish tank.

Changing color

Many sea creatures have the ability to change
their color in very impressive ways. The second program, which I
will cover in its entirety in this lesson, will simulate that process using
a combination of sprite and frame animation. (This will really
be an upgrade to the previous program, and much of the code from the previous
program will be used.)

Because a screen shot cannot represent changes
over time, the screen shot shown in Figure 1 also represents the output
from the program being discussed in this lesson.

Sea worms

The third program, to be discussed in the next
lesson, will use a combination of sprite animation, frame animation, and
some other techniques to cause a group of multi-colored sea worms to slither
around in the fish tank. In addition to slithering, the sea worms
will also change the color of different parts of their body, much like
real sea creatures.

A screen shot of the output from the third program
is shown in Figure 2.

Figure 2. Animated sea worms in a fish tank.

Figure 3 shows the GIF image files that you will need to run these three
programs.

Figure 3. GIF image files that you will need.

Getting the images

You should be able to capture the images by right-clicking on them individually,
and then saving them into files on your local disk. Having done that,
you will need to rename the files to match the names that are hard-coded
into the programs.

Discussion
and Sample Program

Very similar to the previous program

Although this program is quite long, most of the program is identical
to the program named Animate01, which was discussed in the previous
series of lessons.

Only discuss new material

In this lesson, I will discuss only those parts of the program that
are new or different from the previous program. However, I have provided
a copy of the entire program in Listing 8 near the end of the lesson.
You can copy it into a source file on your local disk, compile it, run
it, and see the results.

Because I will be discussing only that code that is new or different,
it may be necessary for you to go back and study the previous program named
Animate01
in order to understand this program.

The makeSprite method

This program differs from the previous program in only two areas:

The Sprite class from which new sprites are instantiated.

The makeSprite method of the controlling class, which is used to
create new sprites.

Listing 1 shows an abbreviated version of the controlling class with all
of the code other than the new method named makeSprite removed for
brevity.

The primary difference between this program and the previous program
named Animate01 can be summarized as follows:

Each Sprite had only one image

Each Sprite object in the previous program had an instance variable
of type Image. The image whose reference was stored in the
instance variable was used to provide the visual manifestation of the sprite
on the screen. Because a given sprite owned a reference to only a
single image, that sprite always looked the same on the screen.

Each Sprite has an array of images

In this program, each Sprite object has an instance variable,
which is a reference to an array of references to Image objects.

The images stored in the Image objects are used to provide the
visual manifestation of the sprites when they appear on the screen.
However, because each sprite now owns references to more than one image,
the sprite is able to change how it looks over time by using different
images as its visual manifestation.

What is an animation frame?

Each of the images in the array is typically referred to as a frame.
The process of causing a sprite to cycle through the frames, changing the
way that it looks in the process, is often referred to as frame animation.

(Note that the use of the word frame in this context has nothing
to do with the Java class named Frame.)

The substantive changes

All of the substantive changes in this program were made in the class
named Sprite. However, because the argument list for the constructor
of the Sprite class changed (to accommodate more incoming information),
it was also necessary to modify the method named makeSprite shown
in Listing 1.

The changes that were made had to do with changes to the parameter list
for the Sprite constructor. The new parameter list includes
a reference to an array of references to Image objects
(gifImages)
along
with some other new parameters that deal with the manner in which the sprite
cycles through the frames.

The Sprite class

As before, the Sprite class is the workhorse of this animation
program.

Each of the sprites swimming around in the fish tank is an object of
the class named Sprite. As is the typical objective in object-oriented
programming, a sprite knows how to take care of itself.

Where are you?

For example, an object of the Sprite class knows how to tell
other objects about the space that it occupies in the fish tank.

What is your speed and direction?

It knows how to tell other objects about its motion vector, which determines
the speed and direction of its motion.

It knows how to use its motion vector in conjunction with a random number
generator to incrementally advance its position to the next location in
its movement through the water. In so doing, it knows how to protect
itself from excessive speed.

Oops, just hit a wall!

It knows what to do if it runs into one of the walls of the fish tank.
Basically, it bounces off the wall much like a pool ball bounces off the
cushions on a pool table. When this happens, it modifies its motion
vector accordingly.

Please draw a picture of yourself

When requested to do so, it knows how to draw itself onto a graphics
context that it receives along with the request.

Did we just collide?

When requested to do so, it can determine if it has collided with another
sprite whose reference it receives along with the request.

Change your appearance

Finally, this new and improved sprite knows how to use an array of images
to change how it looks over time.

This is a very key class insofar as this program is concerned.
The behavior of the methods in this class determines the overall behavior
of the animation process.

Discuss in fragments

As usual, I will discuss the program in fragments.

Most of the code in this revised Sprite class is identical to
the code in the Sprite class used in the previous program named
Animate01.
In keeping with the spirit of this lesson, I will not discuss the code
that I discussed in the previous lessons. Rather, for the most part,
I will discuss only that code that is new or different. When you
see //... in the code fragments, that means that code was omitted
for brevity.

The beginning of the Sprite class

Listing 2 shows the beginning of the Sprite class along with
some new or different declarations for instance variables.

In the earlier version, the reference variable named image was
of type Image. However, in this version, it is of type Image[].
In other words, it previously referred to a single object of type Image.
Now it refers to an array of references to Image objects.

The constructor

Listing 3 shows the signature for the constructor. The significant
thing about Listing 3 is the makeup of the formal argument list, which
I will discuss below.

The constructor for the new Sprite class takes seven parameters,
as opposed to only four parameters for the previous version.

As before, the first parameter is a reference to a Component
object. In fact, this parameter is assumed to be a reference to the
Frame
object in which this animation is run.

This parameter is used to determine the size of the Frame.
It is also used as a required
ImageObserver in some of the methods
in the class. (I discussed image observers in an earlier lesson in this
series.)

An array of Image references

Whereas previously, the second parameter was a reference to an object
of type Image, the second parameter in the new version is a reference
to an array containing references of objects of type Image.

The images in the array are used to provide a visual manifestation for
the sprite, and that visual manifestation changes over time.

Cycling through the animation frames

The third, fourth, and fifth parameters are new to this version of the
Sprite
class. These parameters are used to determine how the sprite cycles
through the set of images in the array.

The startingFrame parameter

The parameter named startingFrame specifies the first frame to
use at the beginning of the frame animation process. In effect, this
determines the color of a sprite when it first appears on the screen.
If you examine the code in Listing 8 near the end of this lesson, you will
see that different values are used for the fifteen sprites that populate
the fish tank.

The frameDisplayIncrement parameter

The parameter named frameDisplayIncrement allows for skipping
some of the images in the array of images.

In this program, this value was set to 1 for all sprites. Thus,
when cycling through the images, each sprite uses every image as its visual
manifestation.

The frameDisplayDuration parameter

The parameter named frameDisplayDuration is used to determine
how long a given image will be used as the visual manifestation for a sprite.

In this program, this value was specified as a random number with a
maximum value of 20 for each new sprite. Thus, each sprite will cycle
through the six images in the array at a different rate.

Same as previous parameters

The sixth and seventh parameters for the new constructor are the same
as the third and fourth parameters of the constructor in the previous program.
The sixth parameter named position specifies the initial position
of the sprite.

The seventh parameter named motionVector is a motion vector,
which determines the initial speed and direction of motion for a new Sprite,
object.

Some new code

Listing 4 shows some of the code in the constructor that is new to this
version of the program.

The first two statements in Listing 4 simply save the incoming values
for startingFrame and frameDisplayIncrement in the appropriate
instance variables.

Duration must be positive

The code having to do with the frameDisplayDuration does two
things. First it uses the abs method of the Math class
to guarantee that the duration is a positive value.

Minimum duration is five animation cycles

Second, it guarantees that the value is at least 5. This means
that each sprite object will use an Image object as its visual manifestation
for at least five animation cycles (or about one-half second at twelve
frames per second).

In this program, this means that each sprite will remain the same color
for at least five animation cycles.

The frameDurationCounter

As you may have surmised earlier, the instance variable named frameDurationCounter
is used to determine when a sprite chooses a new Image object as
its visual manifestation (when it changes color in this program). The
value of the frameDurationCounter is initialized in the code of
Listing 4.

All of the remain code in the constructor is essentially the same as
in the previous version of the program, so I won't discuss it here.

The incFrame method

That brings us to a method named incFrame, which is completely
new to this version of the program. The entire method is shown in
Listing 5.

Later we will see that this method is invoked each time the sprite is
requested to update its location on the screen (once during each animation
cycle).

Decrement the frameDurationCounter

The code in this method is fairly ugly, particularly in this narrow
publication format.

When you wade through it, you discover that it decrements the frameDurationCounter,
(which was initialized to the value of the frameDisplayDuration) each
time the incFrame method is invoked.

Reset the counter and increase the frame variable

When the counter hits zero,

The counter is reset back to the value of the frameDisplayDuration

The value of the variable named frame is increased by the value
of the frameDisplayIncrement

Choose an image

Later we will see that the value of frame is used to choose an
image from the array of images as the visual manifestation of the sprite.

Bracket the value of the frame variable

Some testing is done to ensure that the value for frame is not
greater than the number of images in the array of images and is not less
than zero. If so, the value of frame is corrected appropriately.

Frame control code

This is essentially the control code that determines how the sprite
cycles through the array of images, selecting an image for its visual manifestation
during each animation cycle. There are only about two more statements
in the entire Sprite class that have anything to do with frame animation.
The first of those appears in Listing 6.

Revised updatePosition method

The code in Listing 6 shows the beginning of the revised updatePosition
method of the Sprite class.

You may recall from the previous lessons that this is the method that
the SpriteManager invokes, once during each animation cycle, to
cause each individual sprite to draw itself on the screen in its new position.

As you can see, the first statement in this new version of the method
invokes the incFrame method discussed above to cause the value of
the variable named frame to change when appropriate.

As you can also see, a great deal of code that is essentially the same
as in the previous program was deleted for brevity, taking us all the way
down to the revised method named drawSpriteImage shown in Listing
7.

The revised drawSpriteImage method

As you may recall from the previous lessons, the drawSpriteImage
method is the method that the SpriteManager invokes on each Sprite
object to cause the sprite to draw itself onto the offscreen graphics context
once during each animation cycle

The difference between the new version of the drawSpriteImage
method and the previous version is so important that I have provided the
previous version in a different color in Listing 8 below for comparison.

The thing to note in these two listings is the invocation of the drawImage
method. In both versions, the first parameter to the drawImage
method is a reference to the Image object that will be rendered
onto the screen as the visual manifestation of the sprite.

One Image object available

However, in the previous version of the program, this is a reference
to a single Image object passed into the Sprite constructor
when the Sprite object was instantiated.

A choice of Image objects

In the new version, this is a reference extracted from an array of references
using the frame variable as an index into the array.

The reference to the array of Image objects was received as an
incoming parameter to the constructor when the Sprite object was
instantiated. In the new version, the incFrame method discussed
earlier is used to establish the value stored in frame, which identifies
the Image object that is used to provide the visual manifestation
for the sprite during each animation cycle.

Six colored spheres

In this program, the array contains references to images of six small
spheres of different colors. As the animation progresses and the
incFrame
method controls the value of the variable named frame, different
colored spheres are selected as the visual manifestation of a sprite, and
the sprites appear to change color over time.

The remaining code in the Sprite class was discussed in earlier
lessons and therefore won't be discussed further here.

Summary

In this lesson, I have taught you how to achieve frame animation in Java.
I accomplished this by showing you how to upgrade the sprite animation
program from the earlier lessons into a new program that provides both
sprite animation and frame animation.

What's Next?

In the next lesson in this series, I will provide an additional upgrade
to convert the spherical sea creatures into sea worms that have the ability
to slither around in the fish tank and to change the colors of different
parts of their bodies in a random fashion as they slither.

About the author

Richard Baldwin
is a college professor (at Austin Community College in Austin, TX) and
private consultant whose primary focus is a combination of Java and XML.
In addition to the many platform-independent benefits of Java applications,
he believes that a combination of Java and XML will become the primary
driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects involving
Java, XML, or a combination of the two. He frequently provides onsite
Java and/or XML training at the high-tech companies located in and around
Austin, Texas. He is the author of Baldwin's Java Programming Tutorials,
which has gained a worldwide following among experienced and aspiring Java
programmers. He has also published articles on Java Programming in Java
Pro magazine.

Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology
to real-world problems.