See the picture of the little cat? Click on it. And click on it again. And again. And again.
Now if you could click fast enough and the system could respond fast enough, you might just perceive motion. That's the idea behind a simple form of animation: Show a sequence of still pictures rapidly enough and the viewer can believe that this is a moving picture. We'll see this in the next section. But first, let's look at how we might store a bunch of pictures for showing one after another.
First of all, look up the classes Toolkit and Graphics in the Java API documentation. In particular, note the two methods getImage(..) and drawImage(..). The first can be use to load an image form, say, a .gif file. The second can be used to draw it on your frame or applet or whatever. But what exactly is an image? Again, look in the API documentation to find out more than you ever wanted to know about java.awt.Image.
If we want a bunch of pictures, it would be nice to have a class where we have direct access to an image, and also can get access to the rest of the images.
Of course, we could use any Collection, but, just for the heck of it, let's create our own version of Linked List in Java. It's specifically a linked list of images:
import java.awt.*; public class Images { // A list of images -- myImage is here and a link to the rest Image myImage; Images next; // Constructor for the last image in the list public Images(Image i) { myImage = i; next = null; } // Constructor for adding one more to the current list public Images(Image i, Images rest) { myImage = i; next = rest; } // Accessor for the first image in the list public Image head() { return(myImage); } // Accessor for the rest of the images in the list public Images rest() { return(next); } }
Copy that code and save it in a file called Images.java. Compile it to be sure you missed nothing.
Now we want to get the .gifs onto your computer. Get them from awake.gif and similar links. The other files are named right1, right2, scratch1, scratch2, sleep1, sleep2, stop, and yawn (all .gif). See if you can figure an efficient way to copy them all to your own machine. If you prefer, you can load the images in your program from my URL using techniques similar to those discussed in Lab 8.
In any case, copy the images into a directory called images that sits in the same directory that you're developing your code for this class in. The images were published on a disk that accompanied a "Java in 21 days" book. Now let's start writing code for your Neko (that's the name of the cat!) frame. Start the usual way:
import java.awt.*; import java.awt.event.*; public class NVFrame extends Frame {
No questions yet, right?
Now we need variables to hold those images that you've already seen:
Image right1, right2, stop, yawn, scratch1, scratch2, sleep1, sleep2, awake;
Now we need a variable imageSet to refer to our set of pictures, and a variable currentImg to refer to the first of them:
Images currentImg, imageSet; int xpos = 50; int ypos = 50;Those last two ints will be used to position the pictures in our frame.
That's it for data.
Now we'll have a big method that sets everything up for us:
public void init() { this.addWindowListener(new WindowAdapter() { public void windowClosed(WindowEvent e) { System.exit(0); } public void windowClosing(WindowEvent e) { System.exit(0); } });
Easy so far. Now here's something new. This is how we get .gifs into Image variables:
Toolkit toolkit = Toolkit.getDefaultToolkit(); right1 = toolkit.getImage("images/right1.gif"); right2 = toolkit.getImage("images/right2.gif"); stop = toolkit.getImage("images/stop.gif"); yawn = toolkit.getImage("images/yawn.gif"); scratch1 = toolkit.getImage("images/scratch1.gif"); scratch2 = toolkit.getImage("images/scratch2.gif"); sleep1 = toolkit.getImage("images/sleep1.gif"); sleep2 = toolkit.getImage("images/sleep2.gif"); awake = toolkit.getImage("images/awake.gif");
Easy once you know how. The trick is to know that you need a Toolkit in order to load images from disk. That has to do with cross-platform compatibility.
Now we'll insert those individual images into our image set. We'll load the last first -- so the first will be at the head of the list. (Remember how stacks work?)
imageSet = new Images(awake); imageSet = new Images(sleep2, imageSet); imageSet = new Images(sleep1, imageSet); imageSet = new Images(scratch2, imageSet); imageSet = new Images(scratch1, imageSet); imageSet = new Images(yawn, imageSet); imageSet = new Images(stop, imageSet); imageSet = new Images(right2, imageSet); imageSet = new Images(right1, imageSet);
To finish off the rather huge init() method we will set the current image to the first
currentImg = imageSet;and finally dd a listener for mouse clicks to cycle through the pictures
this.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { currentImg = currentImg.rest(); if (currentImg==null) currentImg = imageSet; // begin again repaint(); } });
That's the init() method. Put it all together in your file.
The rest of the program is pretty insignificant compared to that big setup operation. In fact, here's all the code:
public void run() { setBackground(Color.white); repaint(); } public void paint(Graphics g) { if (currentImg != null) g.drawImage(currentImg.head(), xpos, ypos, this); } public static void main(String[] args) { NVFrame n = new NVFrame(); n.setSize(200,200); n.show(); n.init(); n.run(); }
Put everything together, use emacs and its formatting to help you ensure that your brackets are all closing in the right places. Compile and run. It should give you a frame that behaves just like this applet (repeated here for your convenience).