![]() |
![]() |
What's that elfish?
We start by defining a very general, abstract class for sprites.frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%webster sprite sprite \'spr[0xF5]^-t\ n [ME sprit, fr. MF esprit, fr. L spiritus spirit -- more at SPIRIT] (14c) 1a archaic: SOUL 1b: a disembodied spirit: GHOST 2a: ELF, FAIRY 2b: an elfish person frilled.cs.indiana.edu%
We then describe a more specialized (two-dimensional) type of sprite.frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld Sprite.java -rw-r--r-- 1 dgerman 758 Nov 4 23:05 Sprite.java frilled.cs.indiana.edu%cat Sprite.java import java.awt.*; abstract class Sprite { protected boolean visible; // is sprite visible protected boolean active; // is sprite updatable // abstract methods: abstract void paint (Graphics g); abstract void update(); // accessor methods: public boolean isVisible() { return visible; } public void setVisible(boolean b) { visible = b; } public boolean isActive() { return active; } public void setActive(boolean b) { active = b; } // suspend the sprite public void suspend() { setVisible(false); setActive(false); } // restore the sprite public void restore() { setVisible(true); setActive(true); } } frilled.cs.indiana.edu%
And then we specialize this description even further:frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld Sprite2D.java -rw-r--r-- 1 dgerman 393 Nov 4 23:20 Sprite2D.java frilled.cs.indiana.edu%cat Sprite2D.java import java.awt.*; abstract class Sprite2D extends Sprite { protected int locx; protected int locy; Color color; boolean fill; public boolean getFill() { return fill; } public void setFill(boolean b) { fill = b; } public void setColor(Color c) { color = c; } public Color getColor() { return color; } } frilled.cs.indiana.edu%
Finally, we describe what a bouncing rectangle is to us.frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld RectSprite.java -rw-r--r-- 1 dgerman 728 Nov 4 23:45 RectSprite.java frilled.cs.indiana.edu%cat RectSprite.java import java.awt.*; class RectSprite extends Sprite2D { protected int width, height; // dimensions of rectangle public RectSprite(int x,int y,int w,int h,Color c) { locx = x; locy = y; width = w; height = h; color = c; fill = false; // default: don't fill restore(); // restore the sprite } // provide implementation of abstract methods: public void update() { // does nothing } // check if sprite's visible before painting public void paint(Graphics g) { if (visible) { g.setColor(color); if (fill) { g.fillRect(locx,locy,width,height); } else { g.drawRect(locx,locy,width,height); } } } } frilled.cs.indiana.edu%
A description of the moveable interface is needed.frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld Bouncing* -rw-r--r-- 1 dgerman 1100 Nov 4 23:45 BouncingRect.java frilled.cs.indiana.edu%cat Bouncing.java import java.awt.*; class BouncingRect extends RectSprite implements Moveable { // the coords at which // the rectangle bounces protected int max_width; protected int max_height; // sprite velocity. used to implement Moveable interface protected int vx; protected int vy; public BouncingRect(int x,int y,int w,int h,Color c, int max_w,int max_h) { super(x,y,w,h,c); max_width = max_w; max_height = max_h; } public void setPosition(int x,int y) { locx = x; locy = y; } public void setVelocity(int x,int y) { vx = x; vy = y; } // update position according to velocity public void updatePosition() { locx += vx; locy += vy; } // move and bounce rectangle if it hits borders public void update() { // flip x velocity if it hits left or right bound if ((locx + width > max_width) || locx < 0) { vx = -vx; } // flip y velocity if it hits top or bottom bound if ((locy + height > max_height) || locy < 0) { vy = -vy; } updatePosition(); } } frilled.cs.indiana.edu%
So now we can write an applet.frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld Move* -rw-r--r-- 1 dgerman 170 Nov 4 23:38 Moveable.java frilled.cs.indiana.edu%cat Move*.java interface Moveable { public abstract void setPosition(int c, int d); public abstract void setVelocity(int x, int y); public abstract void updatePosition(); } frilled.cs.indiana.edu%
Andfrilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld Bounce.java Seven.html -rw-r--r-- 1 dgerman 2357 Nov 4 23:48 Bounce.java -rw-r--r-- 1 dgerman 247 Nov 4 23:49 Seven.html frilled.cs.indiana.edu%cat Bounce.java import java.applet.*; import java.awt.*; public class Bounce extends Applet implements Runnable { Thread animation; Graphics offscreen; Image image; static final int NUM_SPRITES = 3; static final int REFRESH_RATE = 80; // in ms Sprite sprites[]; // sprite array int width, height; // applet dimensions public void init() { System.out.println(">> init <<"); setBackground(Color.black); // applet background width = bounds().width; // set applet dimensions height = bounds().height; initSprites(); image = createImage(width,height); // make offscreen buffer offscreen = image.getGraphics(); } public void initSprites() { sprites = new Sprite[NUM_SPRITES]; // init sprite array // define sprite for border sprites[0] = new RectSprite(0,0,width-1,height-1,Color.green); sprites[1] = new BouncingRect(0,0,30,30,Color.yellow, width-1,height-1); sprites[2] = new BouncingRect(17,17,13,13,Color.red, width-1,height-1); ((Moveable)sprites[1]).setVelocity(4,3); ((Moveable)sprites[2]).setVelocity(1,2); ((Sprite2D)sprites[2]).setFill(true); // fill this sprite } public void start() { System.out.println("Starting... "); animation = new Thread(this); if (animation != null) { animation.start(); } } // CALL EACH SPRITE'S update() METHOD // DYNAMIC METHOD BINDING OCCURS HERE! public void updateSprites() { for (int i=0; i<sprites.length; i++) { sprites[i].update(); // call each sprite's update() method } } // override update so it doesn't erase screen public void update(Graphics g) { paint(g); } public void paint(Graphics g) { offscreen.setColor(Color.black); offscreen.fillRect(0,0,width,height); // clear buffer for (int i=0; i<sprites.length; i++) { sprites[i].paint(offscreen); // paint each rectangle } g.drawImage(image,0,0,this); } public void run() { while (true) { repaint(); updateSprites(); try { Thread.sleep (REFRESH_RATE); } catch (Exception exc) { }; } } public void stop() { System.out.println("Stopping... "); if (animation != null) { animation.stop(); animation = null; } } } frilled.cs.indiana.edu%cat Seven.html <html> <head><title>Bouncing... </title></head> <body bgcolor=white> Sprites bouncing... (see the notes) <p> <applet code="Bounce.class" width=300 height=300> </applet>Dedicated to Michael Jordan. <p> </body> </html> frilled.cs.indiana.edu%
This is a diagram of the program so far.
We now change it, as follows. You will soon see why.
Classes already there have been downplayed with a pink shade of lightgrey.
So we can better focus on the new addition, which we present below.
We therefore need to present only three new classes and an HTML file.
An image will be used:
A sound file will be used as well.
And
here's the applet.
Let's now post the code. There are three new classes in all:
The HTML file for this applet is here:frilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/three frilled.cs.indiana.edu%ls -ld *.java -rw-r--r-- 1 dgerman 696 Nov 5 12:33 BitmapSprite.java -rw-r--r-- 1 dgerman 2357 Nov 4 23:48 Bounce.java -rw-r--r-- 1 dgerman 1116 Nov 5 13:08 BouncingBitmap.java -rw-r--r-- 1 dgerman 1100 Nov 4 23:45 BouncingRect.java -rw-r--r-- 1 dgerman 2914 Nov 5 17:12 BouncingSushi.java -rw-r--r-- 1 dgerman 170 Nov 4 23:38 Moveable.java -rw-r--r-- 1 dgerman 728 Nov 4 23:45 RectSprite.java -rw-r--r-- 1 dgerman 758 Nov 4 23:05 Sprite.java -rw-r--r-- 1 dgerman 393 Nov 4 23:20 Sprite2D.java frilled.cs.indiana.edu%cat BouncingSushi.java import java.applet.*; import java.awt.*; public class BouncingSushi extends Applet implements Runnable { Thread animation; Graphics offscreen; Image image; AudioClip a; static final int NUM_SPRITES = 6; static final int REFRESH_RATE = 80; // in ms Sprite sprites[]; // sprite array int width, height; // applet dimensions public void init() { System.out.println("Initializing... "); width = bounds().width; // set applet dimensions height = bounds().height; initSprites(); image = createImage(width,height); // make offscreen buffer offscreen = image.getGraphics(); } public void initSprites() { sprites = new Sprite[NUM_SPRITES]; // init sprite array // define sprite for border sprites[5] = new RectSprite(0,0,width-1,height-1,Color.green); sprites[1] = new BouncingRect(0,0,30,30,Color.yellow, width-1,height-1); sprites[2] = new BouncingRect(17,17,13,13,Color.red, width-1,height-1); // border of the smaller box sprites[3] = new RectSprite(0,0,114,114,Color.green); // this rect bounces in a smaller box! sprites[4] = new BouncingRect(13,13,17,17,Color.green, 114,114); sprites[0] = new BouncingBitmap(37,37, getImage(getCodeBase(), "MM.jpg"), this, width-1,height-1); ((Moveable)sprites[1]).setVelocity(7,5); ((Moveable)sprites[2]).setVelocity(1,2); ((Moveable)sprites[4]).setVelocity(3,4); ((Sprite2D)sprites[4]).setFill(true); // fill this sprite ((Moveable)sprites[0]).setVelocity(4,3); ((BitmapSprite)sprites[0]).setSize(134,168); } public void start() { System.out.println("Starting... "); animation = new Thread(this); if (animation != null) { animation.start(); } a = getAudioClip(getCodeBase(), "Sound.au"); a.loop() ; // loop the sound } // CALL EACH SPRITE'S update() METHOD // DYNAMIC METHOD BINDING OCCURS HERE! public void updateSprites() { for (int i=0; i<sprites.length; i++) { sprites[i].update(); // call each sprite's update() method } } // override update so it doesn't erase screen public void update(Graphics g) { paint(g); } public void paint(Graphics g) { offscreen.setColor(Color.black); offscreen.fillRect(0,0,width,height); // clear buffer for (int i=0; i<sprites.length; i++) { sprites[i].paint(offscreen); // paint each rectangle } g.drawImage(image,0,0,this); } public void run() { while (true) { repaint(); updateSprites(); try { Thread.sleep (REFRESH_RATE); } catch (Exception exc) { }; } } public void stop() { System.out.println("Stopping... "); a.stop(); // stop the sound if (animation != null) { animation.stop(); animation = null; } } } frilled.cs.indiana.edu%cat BitmapSprite.java import java.applet.*; import java.awt.*; class BitmapSprite extends Sprite { protected int locx; protected int locy; // image dimensions protected int width,height; protected Image image; // the bitmap protected Applet applet; // the parent applet public BitmapSprite(int x,int y,Image i,Applet a) { locx = x; locy = y; image = i; applet = a; restore(); } public void setSize(int w,int h) { width = w; height = h; } public void update() { // do nothing } public void paint(Graphics g) { if (visible) { g.drawImage(image,locx,locy,applet); } } } frilled.cs.indiana.edu%cat BouncingBitmap.java import java.applet.*; import java.awt.*; class BouncingBitmap extends BitmapSprite implements Moveable { // the coords at which the bitmap bounces protected int max_width; protected int max_height; // sprite velocity. used to implement Moveable interface protected int vx; protected int vy; public BouncingBitmap(int x,int y,Image i,Applet a, int max_w,int max_h) { super(x,y,i,a); max_width = max_w; max_height = max_h; } public void setPosition(int x,int y) { locx = x; locy = y; } public void setVelocity(int x,int y) { vx = x; vy = y; } // update position according to velocity public void updatePosition() { locx += vx; locy += vy; } // move and bounce rectangle if it hits borders public void update() { // flip x velocity if it hits left or right bound if ((locx + width > max_width) || locx < 0) { vx = -vx; } // flip y velocity if it hits top or bottom bound if ((locy + height > max_height) || locy < 0) { vy = -vy; } updatePosition(); } } frilled.cs.indiana.edu%javac BouncingSushi.java Note: BouncingSushi.java uses or overrides a deprecated API. Note: Recompile with -deprecation for details. frilled.cs.indiana.edu%ls -ld *.class -rw-r--r-- 1 dgerman 857 Nov 5 17:09 BitmapSprite.class -rw-r--r-- 1 dgerman 2633 Nov 5 17:09 Bounce.class -rw-r--r-- 1 dgerman 901 Nov 5 17:12 BouncingBitmap.class -rw-r--r-- 1 dgerman 875 Nov 5 17:12 BouncingRect.class -rw-r--r-- 1 dgerman 3265 Nov 5 17:31 BouncingSushi.class -rw-r--r-- 1 dgerman 180 Nov 5 17:09 Moveable.class -rw-r--r-- 1 dgerman 804 Nov 5 17:09 RectSprite.class -rw-r--r-- 1 dgerman 700 Nov 5 17:09 Sprite.class -rw-r--r-- 1 dgerman 568 Nov 5 17:09 Sprite2D.class frilled.cs.indiana.edu%ls -ld *.jpg *.au -rw-r--r-- 1 dgerman 4550 Nov 5 14:24 MM.jpg -rw-r--r-- 1 dgerman 28106 Nov 5 12:21 Sound.au frilled.cs.indiana.edu%
In this chapter you've learned about abstract classes and interfaces and how they permit the clean, modular design of applets. In particular you've created<html> <head><title>A Weird Applet...</title></head> <body bgcolor=white> This <em>may</em> look a bit weird, but that's OK, because it <em>is</em> weird... <p> <applet code="BouncingSushi.class" width=300 height=300> </applet> <p> Dedicated to Andy Kauffman. </body> </html>
Sprite
classes
that you'll use in your first Java game (which is coming up really soon!). And you now know how
to use bitmaps, which are important in creating customized looks for your graphics applets. You
also saw how you can include sounds in your applets. Next you will see how to take control of
your sprites.