|
|
We start by discussing threads, and the universal animation loop.
Here they are, in combined action.
frilled.cs.indiana.edu%pwd
/nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/two
frilled.cs.indiana.edu%ls -ld Broad* Three*
-rw-r--r-- 1 dgerman 2169 Nov 4 16:37 Broadway.java
-rw-r--r-- 1 dgerman 503 Nov 4 17:01 Three.html
frilled.cs.indiana.edu%cat Three.html
<html>
<title> Using Objects for Animation </title>
<body bgcolor=white>
<p>
This animation lasts forever. When you're done looking at
it simply go back to the page you came from. Your browser
will know to stop the applet when you leave this page.
Please notice the flicker... <p>
<applet code="Broadway.class" width=300 height=300>
</applet>
<p> <em>Broadway Boogie Woogie</em>, dedicated to Piet Mondrian.
</body>
</html>
frilled.cs.indiana.edu%cat Broadway.java
import java.applet.*;
import java.awt.*;
public class Broadway extends Applet implements Runnable {
Thread animation;
int locx,locy; // location of rectangle
int width, height; // dimensions of rectangle
static final byte UP = 0; // direction of motion
static final byte DOWN = 1;
static final byte LEFT = 2;
static final byte RIGHT = 3;
byte state; // state the rect is in (up, down, left, right)
static final int REFRESH_RATE = 100;
// length of pausing interval (in ms)
public void init() {
System.out.println("Initializing... ");
setBackground(Color.black);
locx = 80; locy = 100;
width = 110; height = 90;
state = UP;
}
public void start() {
System.out.println("Starting... ");
animation = new Thread(this); // see run() below...
if (animation != null) {
animation.start();
}
}
public void paint(Graphics g) {
System.out.println("Painting... ");
g.setColor(Color.yellow);
g.fillRect(0,0,90,90);
g.fillRect(250,0,40,190);
g.fillRect(80,110,100,20); // hidden rectangle
g.setColor(Color.blue);
g.fillRect(80,200,220,90);
g.fillRect(100,10,90,80);
g.setColor(Color.lightGray);
g.fillRect(locx,locy,width,height);
g.setColor(Color.red);
g.fillRect(200,0,45,45);
g.fillRect(0,100,70,200);
g.setColor(Color.magenta);
g.fillRect(200,55,60,135);
}
void updateRectangle() {
switch (state) {
case DOWN:
locy += 2;
if (locy >= 110) {
state = UP;
}
break;
case UP:
locy -= 2;
if (locy <= 90) {
state = RIGHT;
}
break;
case RIGHT:
locx += 2;
if (locx >= 90) {
state = LEFT;
}
break;
case LEFT:
locx -= 2;
if (locx <= 70) {
state = DOWN;
}
break;
}
}
public void run() {
while (true) {
repaint();
updateRectangle();
try {
Thread.sleep (REFRESH_RATE);
} catch (Exception e) {
};
}
}
public void stop() {
System.out.println("Stopping... ");
if (animation != null) {
animation.stop();
animation = null;
}
}
}
frilled.cs.indiana.edu%javac Broad*.java
Note: Broadway.java uses or overrides a deprecated API.
Note: Recompile with -deprecation for details.
frilled.cs.indiana.edu%ls -ld Broad*
-rw------- 1 dgerman 2173 Nov 4 17:02 Broadway.class
-rw-r--r-- 1 dgerman 2169 Nov 4 16:37 Broadway.java
frilled.cs.indiana.edu%
Here's the applet in action. (Notice the
flicker). To eliminate the flicker we apply double-buffering.
frilled.cs.indiana.edu%pwd
/nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/two
frilled.cs.indiana.edu%ls -ld Four* Broad*DB.java
-rw-r--r-- 1 dgerman 2593 Nov 4 17:20 BroadwayDB.java
-rw-r--r-- 1 dgerman 352 Nov 4 17:19 Four.html
frilled.cs.indiana.edu%cat Four.html
<html>
<head><title>A Better Boogie Woogie</title></head>
<body bgcolor="white">
This is the animation from before, with double buffering. No flicker... <p>
<applet code="BroadwayDB.class" width=300 height=300>
</applet>
<p> <em>A Better Boogie Woogie</em>, also dedicated to Piet Mondrian <p>
</body>
</html>
frilled.cs.indiana.edu%cat Broad*DB.java
import java.applet.*;
import java.awt.*;
// double buffered and clipped
public class BroadwayDB extends Applet implements Runnable {
Thread animation;
int locx,locy; // location of rectangle
int width, height; // dimensions of rectangle
static final byte UP = 0; // direction of motion
static final byte DOWN = 1;
static final byte LEFT = 2;
static final byte RIGHT = 3;
Graphics offscreen;
Image image;
byte state; // state the rect is in (same as before)
static final int REFRESH_RATE = 100; // (that is, in ms)
public void init() {
System.out.println("Initializing... ");
setBackground(Color.black);
locx = 80;
locy = 100;
width = 110;
height = 90;
state = UP;
image = createImage(300,300);
offscreen = image.getGraphics();
}
public void start() {
System.out.println("Starting... ");
animation = new Thread(this);
if (animation != null) {
animation.start();
}
}
public void update(Graphics g) { // this is new...
g.clipRect(70,90,130,110);
paint(g);
}
public void paint(Graphics g) {
System.out.println("Painting... ");
offscreen.setColor(Color.black);
offscreen.fillRect(0,0,300,300); // clear buffer
offscreen.setColor(Color.yellow);
offscreen.fillRect(0,0,90,90);
offscreen.fillRect(250,0,40,190);
offscreen.fillRect(80,110,100,20);
offscreen.setColor(Color.blue);
offscreen.fillRect(80,200,220,90);
offscreen.fillRect(100,10,90,80);
offscreen.setColor(Color.lightGray);
offscreen.fillRect(locx,locy,width,height);
offscreen.setColor(Color.red);
offscreen.fillRect(200,0,45,45);
offscreen.fillRect(0,100,70,200);
offscreen.setColor(Color.magenta);
offscreen.fillRect(200,55,60,135);
g.drawImage(image,0,0,this);
}
void updateRectangle() {
switch (state) {
case DOWN:
locy += 2;
if (locy >= 110) {
state = UP;
}
break;
case UP:
locy -= 2;
if (locy <= 90) {
state = RIGHT;
}
break;
case RIGHT:
locx += 2;
if (locx >= 90) {
state = LEFT;
}
break;
case LEFT:
locx -= 2;
if (locx <= 70) {
state = DOWN;
}
break;
}
}
public void run() {
while (true) {
repaint();
updateRectangle();
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%javac BroadwayDB.java
Note: BroadwayDB.java uses or overrides a deprecated API.
Note: Recompile with -deprecation for details.
frilled.cs.indiana.edu%ls -ld Broad*DB.*
-rw------- 1 dgerman 2702 Nov 4 17:21 BroadwayDB.class
-rw-r--r-- 1 dgerman 2593 Nov 4 17:20 BroadwayDB.java
-rw-r--r-- 1 dgerman 2667 Nov 4 17:15 BroadwayDB.java~
frilled.cs.indiana.edu%
Here's the applet in action. (Do you see any
flicker?)Let's now redesign the interior of the applet.
frilled.cs.indiana.edu%pwd
/nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/two
frilled.cs.indiana.edu%ls -ld Five.html Chicago.java
-rw-r--r-- 1 dgerman 1757 Nov 4 18:20 Chicago.java
-rw-r--r-- 1 dgerman 347 Nov 4 18:30 Five.html
frilled.cs.indiana.edu%cat Five.html
<html>
<head><title>An Object-Oriented Boogie</title></head>
<body bgcolor=white>
This is the same Mondrian of before, only the inside is different. <p>
<applet code="Chicago.class" width=300 height=300>
</applet>
<p> Applet called Chicago, uses DancingRect, a standing still dancer. <p>
</body>
</html>
frilled.cs.indiana.edu%cat Chicago.java
import java.applet.*;
import java.awt.*;
// An Object-Oriented Boogie.
public class Chicago extends Applet {
static final int NUM_RECTS = 9;
DancingRect r[]; // defined below
public void init() {
System.out.println("Initializing... ");
setBackground(Color.black);
initRectangles();
}
public void initRectangles() {
// allocate dancing rectangles
r = new DancingRect[NUM_RECTS];
r[0] = new DancingRect(0,0,90,90,Color.yellow);
r[1] = new DancingRect(250,0,40,190,Color.yellow);
r[2] = new DancingRect(200,55,60,135,Color.yellow);
r[3] = new DancingRect(80,200,220,90,Color.blue);
r[4] = new DancingRect(100,10,90,80,Color.blue);
r[5] = new DancingRect(80,100,110,90,Color.lightGray);
r[6] = new DancingRect(200,0,45,45,Color.red);
r[7] = new DancingRect(0,100,70,200,Color.red);
r[8] = new DancingRect(200,55,60,135,Color.magenta);
}
public void start() {
System.out.println("Starting... ");
}
public void paint(Graphics g) {
for (int i=0; i<NUM_RECTS; i++) {
r[i].paint(g); // paint each rectangle
}
}
public void stop() {
System.out.println("Stopping... ");
}
}
class DancingRect {
int locx, locy;
// (locx,locyy) are coordinates of upper left corner of rectangle
int width, height; // width and height of rectangle
Color myColor; // color of rectangle
public DancingRect(int x,int y,int w,int h,Color c) {
locx = x;
locy = y;
width = w;
height = h;
myColor = c;
}
public void danceStep() {
// does nothing
}
public void paint(Graphics g) {
g.setColor(myColor);
g.fillRect(locx,locy,width,height);
}
}
frilled.cs.indiana.edu%javac Chicago.java
frilled.cs.indiana.edu%ls -ld Dan* Chi* Fiv*
-rw-r--r-- 1 dgerman 1396 Nov 4 18:32 Chicago.class
-rw-r--r-- 1 dgerman 1757 Nov 4 18:20 Chicago.java
-rw------- 1 dgerman 679 Nov 4 18:32 DancingRect.class
-rw-r--r-- 1 dgerman 347 Nov 4 18:30 Five.html
frilled.cs.indiana.edu%
The output
should be undistinguishable from the one of the previous version. What follows is an exercise in another one of the fundamental aspects of Java.
We take a look at dynamic method binding. First, we add a few more classes.
Indeed, we have takenfrilled.cs.indiana.edu%pwd /nfs/grouchy/home/user2/www/classes/a348-dger/t540/lectures/two frilled.cs.indiana.edu%ls -ld *.java -rw------- 1 dgerman 1225 Nov 4 19:09 BoogieRect.java -rw-r--r-- 1 dgerman 2169 Nov 4 16:37 Broadway.java -rw-r--r-- 1 dgerman 2593 Nov 4 17:20 BroadwayDB.java -rw-r--r-- 1 dgerman 1215 Nov 4 19:09 Chicago.java -rw------- 1 dgerman 563 Nov 4 19:09 DancingRect.java -rw------- 1 dgerman 2211 Nov 4 19:10 Simphony.java -rw------- 1 dgerman 981 Nov 4 19:09 WaltzRect.java frilled.cs.indiana.edu%
DancingRect
out of the Chicago source code, to
keep each thing into its own.
frilled.cs.indiana.edu%cat BoogieRect.java
import java.awt.*;
class BoogieRect extends DancingRect {
// BoogieRect inherits all instance variables and
// methods from DancingRect
static final byte UP = 0; // direction of motion
static final byte DOWN = 1;
static final byte LEFT = 2;
static final byte RIGHT = 3;
byte state; // state of rectangle
int max_x; // max x value
int min_x; // min x value
int max_y; // max y value
int min_y; // min y value
public BoogieRect(int x,int y,int w,int h,Color c) {
super(x,y,w,h,c); // call superclass constructor
max_x = locx + 13;
min_x = locx - 13;
max_y = locy + 13;
min_y = locy - 13;
}
// override danceStep()
public void danceStep() {
switch (state) {
case DOWN:
locy += 2;
if (locy >= max_y) {
state = UP;
}
break;
case UP:
locy -= 2;
if (locy <= min_y) {
state = RIGHT;
}
break;
case RIGHT:
locx += 2;
if (locx >= max_x) {
state = LEFT;
}
break;
case LEFT:
locx -= 2;
if (locx <= min_x) {
state = DOWN;
}
break;
}
}
}
frilled.cs.indiana.edu%
That was one new class, with its own danceStep. Here's another class, taken directly from Strauss:
frilled.cs.indiana.edu%cat WaltzRect.java
import java.awt.*;
class WaltzRect extends DancingRect {
byte state;
static final byte SE = 0; // going southeast
static final byte NE = 1; // going northeast
static final byte W = 2; // going west
int bottom_x; // the x coordinate of bottom point of the waltz
int right_x; // the x coordinate of right point of the waltz
int left_x; // the x coordinate of left point of the waltz
public WaltzRect(int x,int y,int w,int h,Color c) {
super(x,y,w,h,c); // call superclass constructor
bottom_x = locx + 17;
right_x = bottom_x + 17;
left_x = locx;
}
// override danceStep()
public void danceStep() {
switch (state) {
case SE:
locx++;
locy++;
if (locx == bottom_x) {
state = NE;
}
break;
case NE:
locx++;
locy--;
if (locx == right_x) {
state = W;
}
break;
case W:
locx-- ;
if (locx == left_x) {
state = SE;
}
break;
}
}
}
frilled.cs.indiana.edu%
We now create a visual simphony, nothing less. The picture look like that:
So here's the source code for the applet that puts everything together.
frilled.cs.indiana.edu%cat Simphony.java
import java.applet.*;
import java.awt.*;
public class Simphony extends Applet implements Runnable {
Thread animation;
Graphics offscreen;
Image image;
static final int NUM_RECTS = 9; // in milliseconds
static final int REFRESH_RATE = 100; // in milliseconds
DancingRect r[];
public void init() {
System.out.println("Initializing... ");
setBackground(Color.black);
initRectangles();
image = createImage(bounds().width,bounds().height);
offscreen = image.getGraphics();
}
public void initRectangles() {
// allocate dancing rectangles
r = new DancingRect[NUM_RECTS];
r[0] = new DancingRect(0,0,90,90,Color.yellow);
r[1] = new BoogieRect(250,0,40,190,Color.yellow);
r[2] = new WaltzRect(200,55,60,135,Color.yellow);
r[3] = new BoogieRect(80,200,220,90,Color.blue);
r[4] = new WaltzRect(100,10,90,80,Color.blue);
r[5] = new BoogieRect(80,100,110,90,Color.lightGray);
r[6] = new WaltzRect(200,0,45,45,Color.red);
r[7] = new WaltzRect(0,100,70,200,Color.red);
r[8] = new BoogieRect(200,55,60,135,Color.magenta);
}
public void start() {
System.out.println("Starting... ");
animation = new Thread(this);
if (animation != null) {
animation.start();
}
}
// update each rectangle's position.
// DYNAMIC METHOD BINDING OCCURS HERE!
public void updateRectangles() {
for (int i=0; i<NUM_RECTS; i++) {
r[i].danceStep(); // each rectangles dance step
}
}
// 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,300,300); // clear buffer
for (int i=0; i<NUM_RECTS; i++) {
r[i].paint(offscreen); // paint each rectangle
}
g.drawImage(image,0,0,this);
}
public void run() {
while (true) {
repaint();
updateRectangles();
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 Six.html
<html>
<head><title>A Visual Simphony, Nothing Less... </title></head>
<body bgcolor=white>
<p>A Visual Simphony, Nothing Else... <p>
<applet code="Simphony.class" width=300 height=300>
</applet>
<p>Dedicated to Piet Mondrian and Victor Borge. <p>
</body>
</html>
frilled.cs.indiana.edu%javac Simphony.java
Note: Simphony.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 837 Nov 4 19:10 BoogieRect.class
-rw-r--r-- 1 dgerman 2173 Nov 4 17:02 Broadway.class
-rw-r--r-- 1 dgerman 2702 Nov 4 17:21 BroadwayDB.class
-rw-r--r-- 1 dgerman 1398 Nov 4 19:10 Chicago.class
-rw-r--r-- 1 dgerman 683 Nov 4 19:10 DancingRect.class
-rw-r--r-- 1 dgerman 2620 Nov 4 19:25 Simphony.class
-rw-r--r-- 1 dgerman 746 Nov 4 19:10 WaltzRect.class
frilled.cs.indiana.edu%
And
that should be the end of it.
(Can you hear the music?)