Part 3: What About Images?
Java Game Programming Tutorial
Getting Started
To program in the Java language, you will need to install the free Java Development Kit (JDK) on your system.
You can find the latest version of the JDK, documentation, and online tutorials here at the JDK Download Site.
You will also require a Java-enabled web browser to view the tutorial examples.
My aim is not to teach every aspect of Java programming but to help those with a bit of programming knowledge with graphics and game programming issues in Java relating to web pages and the internet. I hope you find it helpful.
Download javaGameProgrammingTutorialClasses.zip to receive the following classes:
- DBuffer.class
- Flicker.class
- FXCycle.class
- FXImage.class
- Hello.class
- Lines.class
Part 3: What About Images?
One of the most important aspects of animation are images in
various formats. From 2D to 3D software, they are often used
to simulate motion and reduce calculations. Eons ago, little
flipbooks were the technology whereby each page of the book
had a different drawing and the rapid flipping created the
illusion that a character was moving.
It is such a simple principle now inherent in best selling
games and block buster movies. Each image frame just gets
fancier and the 'flipper' has ranged from projection reels
to computers in the past. Now, through the magic of Java
programming, we can build our own animations on the internet
for the entire world to see. I'll show you how.
Since we're going to be dealing with images from this point
forward, I must explain another aspect of building user
friendly applets: the MediaTracker class.
The MediaTracker class monitors the status of media types,
such as images, sounds, etc. A common concern with applets
is that images are sometimes referred to before they are
fully loaded, which has unpredictable results.
MediaTracker can load data asynchronously (in the background)
or synchronously (waits for data to load first). Image loading
is sped up by threads which dedicate themselves to a group of
images identified by a selected ID.
Since the Flicker class adopts many techniques used in Part 2,
I will only go over the changes relevant to image loading and
rendering. This applet also introduces you to parameters which
give applets their flexibility. I will explain these as well.
MediaTracker flickerTracker;
Image[] flickerImages;
The applet requires the variables above: an instance of the
MediaTracker class and an array of image objects.
String paramString;
int flickerStart=0, flickerCount=0;
int flickerDelay=0, flickerFrame=0;
paramString is a string object for storing each parameter value and
the integers are numbers relevant to the image displaying process.
paramString = getParameter("FLICKERDELAY");
flickerDelay = Integer.parseInt(paramString);
This is code in the init method showing how parameters are accessed.
Parameters are defined in web page HTML code, making them variable
without recompiling applets to change some small feature.
getParameter returns the parameter name in the HTML applet tag by
its name ("FLICKERDELAY") as type String. In the case above, a
number is required for the animation delay so we use an Integer
object to convert the parameter string and put it in our variable.
flickerImages = new Image[flickerCount];
Here, the parameter FLICKERCOUNT will tell the applet how many images
to animate and allocate the dynamic memory for the array of images.
flickerTracker = new MediaTracker(this);
The MediaTracker object must also be allocated for usage.
for(int i=0; i>flickerCount; i++) {
flickerImages[i] = getImage(getCodeBase(),
paramString + flickerStart + ".gif");
This is a loop which requests each image in the array be loaded from
the specified file. getCodeBase is the URL location of the applet
and the image filename is reset for the next file. eg.) image1.gif
flickerTracker.addImage(flickerImages[i],0);
flickerStart++;
}
In the same loop, each image object is added to the MediaTracker
object as part of the group ID zero. The counter is incremented
to the next image number.
flickerTracker.checkID(0,true);
repaint();
}
Above, checkID asks the MediaTracker object to load the images
specified by the ID zero and returns immediately. This
asynchronous loading which will occur in the background while
the applet continues its respective stages. Note that repaint
is called which calls the applet's default update method.
if(!flickerTracker.checkAll()) {
g.drawString("Please wait, images loading...",
20,this.size().height/2);
}
This is inside our customized paint method. The MediaTracker
object will return false from checkAll() until all the images
are loaded so this information is used to paint a message for
the user.
else {
g.drawImage(flickerImages[flickerFrame],0,0,
this.size().width,this.size().height,this);
}
Now, when the images have all been loaded, drawImage will be
called to draw the current image in the array at (0,0), scaled
to the applet width and height.
repaint();
flickerFrame++;
if(flickerFrame >= flickerCount) flickerFrame=0;
In Part 2, the applet methods are discussed along with the run
method so I've listed just the animation actions above in the
run method.
Repaint calls update which calls paint which draws the image in
the array. The image counter is incremented to the next image
number and reset to the first if the last image is reached. This
cycles through the images for the life of the applet.
You can reuse this applet with your own gif images numbered in
sequence, (anim1.gif, anim2.gif, anim3.gif, etc...) Here is
example HTML for running this applet using parameters for gif
files anim1.gif to anim3.gif with a delay of 10 milliseconds
between frames:
<APPLET CODE="Flicker.class" WIDTH=50 HEIGHT=50>
<PARAM NAME="FLICKERNAME" VALUE="anim">
<PARAM NAME="FLICKERSTART" VALUE="1">
<PARAM NAME="FLICKERCOUNT" VALUE="3">
<PARAM NAME="FLICKERDELAY" VALUE="10">
</APPLET>
Here is the applet code in its entirety:
// Flicker.java
// by Garry Morse
import java.awt.*;
import java.applet.*;
public class Flicker extends Applet implements Runnable {
Thread flickerThread;
MediaTracker flickerTracker;
Image[] flickerImages;
String paramString;
int flickerStart=0, flickerCount=0;
int flickerDelay=0, flickerFrame=0;
public void init() {
// get parameter for wait delay between images
paramString = getParameter("FLICKERDELAY");
flickerDelay = Integer.parseInt(paramString);
// get parameter for number of image to start with
paramString = getParameter("FLICKERSTART");
flickerStart = Integer.parseInt(paramString);
// get parameter for number of images to load
paramString = getParameter("FLICKERCOUNT");
flickerCount = Integer.parseInt(paramString);
// get parameter for image path and prefix name
paramString = getParameter("FLICKERNAME");
// allocate memory for an array of image objects
flickerImages = new Image[flickerCount];
// create a media tracker object for this applet
flickerTracker = new MediaTracker(this);
// loop for number of images
for(int i=0; i= flickerCount) flickerFrame=0;
// try to shut down thread for milliseconds
try {
flickerThread.sleep(flickerDelay+1);
}
// if exception, output error message
catch(InterruptedException e) {
System.out.println("Thread would not go to sleep.");
}
}
}
}
|