The two fish images are fish1.gif, which points to the left, and fish2.gif, which points to the right. GIF images are a good choice here, because you can draw your images on a transparent background; as the fish move around, the square background on which they're drawn will not appear, because it's transparentonly the fish image will be visible. That means the fish will actually look like fish, not boxes, swimming around. Besides loading the fish images, this is a good time to load the background image of bubbles, because the application needs to know how large that image is so it can size the window correctly. This application comes with a file named bubbles.gif that you can see as the background, as shown in Figure 1.1. However, you can use your own image insteadthe possibilities are endless. To make sure the images are loaded correctly, Aquarium uses a MediaTracker object, which will alert the user if there are problems in loading fish1.gif, fish2.gif, and the background image, bubbles.gif. Here's how the MediaTracker object, tracker, is set up: import java.awt.*; import java.awt.event.*; public class Aquarium extends Frame { MediaTracker tracker; Aquarium() { setTitle("The Aquarium"); tracker = new MediaTracker(this); . . . this.addWindowListener(new WindowAdapter(){ public void windowClosing( WindowEvent windowEvent){ System.exit(0); } } ); } . . . } This application stores the fish and background images in objects of the java.awt.Image class, which is going to be used extensively throughout the chapter. The significant methods of this class appear in Table 1.2.
To load in the images, you can use the getImage method of the AWT's toolkit, a built-in treasure chest of helpful functions. The Toolkit class is abstract and can't be instantiated directly, but you can use the Toolkit class's static method geTDefaultToolkit to get a working toolkit object for the current application. Here's how you can load in the images the application needs, storing the fish images in an array named fishImages and the background image in an image named aquariumImage: import java.awt.*; import java.awt.event.*; public class Aquarium extends Frame { Image aquariumImage; Image[] fishImages = new Image[2]; MediaTracker tracker; Aquarium() { setTitle("The Aquarium"); tracker = new MediaTracker(this); fishImages[0] = Toolkit.getDefaultToolkit().getImage ("fish1.gif"); tracker.addImage(fishImages[0], 0); fishImages[1] = Toolkit.getDefaultToolkit().getImage ("fish2.gif"); tracker.addImage(fishImages[1], 0); aquariumImage = Toolkit.getDefaultToolkit().getImage ("bubbles.gif"); tracker.addImage(aquariumImage, 0); try { tracker.waitForID(0); }catch (Exception ex) { System.out.println(ex.getMessage()); } . . . this.addWindowListener(new WindowAdapter(){ public void windowClosing( WindowEvent windowEvent){ System.exit(0); } } ); } . . . } Now the fish and background images are available in code. You can size the window to match the background image with the setSize method, make sure the window can't be resized (because the background image is of a fixed size) with the setResizable method, and show the window on the screen with the window's setVisible method, as shown in the following code: import java.awt.*; import java.awt.event.*; public class Aquarium extends Frame { Image aquariumImage; Image[] fishImages = new Image[2]; MediaTracker tracker; Aquarium() { setTitle("The Aquarium"); . . . try { tracker.waitForID(0); }catch (Exception ex) { System.out.println(ex.getMessage()); } setSize(aquariumImage.getWidth(this), aquariumImage.getHeight(this)); setResizable(false); setVisible(true); . . . this.addWindowListener(new WindowAdapter(){ public void windowClosing( WindowEvent windowEvent){ System.exit(0); } } ); } . . . } This application will use one more Image object besides the three it already hasmemoryImage. This is where double buffering comes into play; to avoid making the image of the aquarium flicker, the application draws its visual display offscreen and then draws the completed scene on the screen all at once. This means Java can avoid drawing a fish, updating the entire display, drawing another fish, updating the entire display, and so on, which would make the aquarium flicker. You can create this offscreen Image object, memoryImage, in memory. In addition, the application creates a Graphics object, called memoryGraphics, that can be used to draw in the new memory image this way: import java.awt.*; import java.awt.event.*; public class Aquarium extends Frame { Image aquariumImage, memoryImage; Graphics memoryGraphics; Image[] fishImages = new Image[2]; MediaTracker tracker; Aquarium() { . . . setSize(aquariumImage.getWidth(this), aquariumImage.getHeight(this)); setResizable(false); setVisible(true); memoryImage = createImage(getSize().width, getSize().height); memoryGraphics = memoryImage.getGraphics(); this.addWindowListener(new WindowAdapter(){ public void windowClosing( WindowEvent windowEvent){ System.exit(0); } } ); } . . . } The Graphics class is what lets you do all the drawing in this application, and the significant methods of this class (that is, the ones you'll see later in this book) appear in Table 1.3.
Okay, the setup is complete; the images are ready to go, and the window is ready to be used. What about getting the fish to actually start doing something? |