//
import java.awt.*;
import java.util.*;
public class butterflies extends BufferedApplet
{
int N = 8; // NUMBER OF BUTTERFLIES PER ROW
Graphics g;
int width = 0, height = 0;
Color bgColor = new Color(0xff, 0x90, 0x00);
Color shadowColor = bgColor.darker();
Color fgColor[] = new Color[N*N];
double oldTime, rate = .5, var = .5;
double randomSeed[] = new double[N*N];
Random R = new Random();
double rnd() { return Math.abs(R.nextDouble()) % 1.0; } // RANDOM NUMBER BETWEEN ZERO AND ONE
public void render(Graphics g) {
this.g = g;
if (width == 0) {
width = bounds().width;
height = bounds().height;
oldTime = System.currentTimeMillis() / 1000.;
// PICK A RANDOM COLOR FOR EACH BUTTERFLY
for (int i = 0 ; i < N ; i++)
for (int j = 0 ; j < N ; j++) {
int n = N * i + j;
fgColor[n] = new Color((float)(.3+.6*rnd()),(float)(.2+.6*rnd()),(float)(.1+.6*rnd()));
randomSeed[n] = rnd() - .5;
}
}
// HOW MUCH TIME HAS GONE BY SINCE LAST FRAME?
double newTime = System.currentTimeMillis() / 1000.;
double deltaTime = newTime - oldTime;
oldTime = newTime;
// BLANK OUT THE BACKGROUND
g.setColor(bgColor);
g.fillRect(0,0, width, height);
// DRAW ALL THE BUTTERFLIES
for (int i = 0 ; i < N ; i++)
for (int j = 0 ; j < N ; j++) {
int x = i * width / N + width /N/2;
int y = j * height / N + height/N/2;
drawButterfly(deltaTime, i + N * j, x, y, width/(2*N-N/2), width/(2*N-N/2));
}
animating = true; // FORCE APPLET TO REDISPLAY EVERY FRAME
}
// DATA CONTAINING SHAPE OF ONE BUTTERFLY WING
double X[] = {.0, .3, .7 , 1., .9, .85, .6, .7, .4, .2, .0};
double Y[] = {.8, .95, .98, .9, .8, .65, .4, .3, .0, .05, .2};
int iX[] = new int[X.length];
int iY[] = new int[Y.length];
double theta[] = new double[N*N]; // TIME-VARYING FLAP POSITION FOR EACH BUTTERFLY
public void drawButterfly(double deltaTime, int n, int x, int y, int w, int h) {
// COMPUTE HOW MUCH TO PROGRESS THE FLAPPING MOTION FOR THIS BUTTERFLY
theta[n] += rate * deltaTime * (20 + 30 * var * randomSeed[n]);
// COMPUTE HORIZONTAL SCALE FACTOR DUE TO FLAPPING
double s = .4 + .15 * Math.sin(theta[n]);
// COMPUTE THE VERTICAL DISPLAY POSITIONS OF WING VERTICES
for (int i = 0 ; i < X.length ; i++)
iY[i] = y + (int)(h * (.5 - Y[i]));
// DRAW SHADOWS OF WINGS
g.setColor(shadowColor);
for (int i = 0 ; i < X.length ; i++)
iY[i] += w/5;
for (int i = 0 ; i < X.length ; i++)
iX[i] = x + (int)(w * (.03 + s * X[i]) + (.1 + 2*X[i]*(1-s))*w/5);
g.fillPolygon(iX, iY, X.length);
for (int i = 0 ; i < X.length ; i++)
iX[i] = x + (int)(w * (-.03 - s * X[i]) + (.1 + 2*X[i]*(1-s))*w/5);
g.fillPolygon(iX, iY, X.length);
for (int i = 0 ; i < X.length ; i++)
iY[i] -= w/5;
// DRAW BUTTERFLY'S BODY
g.setColor(Color.black);
g.fillOval(x-w/20, y-h/2+h/8, w/10, h);
// DRAW ANTENNAE
int a = (int)(.05 * w * Math.sin(.4 * theta[n]));
g.drawLine(x, y-h/3, x-w/4 + a, y-h/2-h/4);
g.drawLine(x, y-h/3, x+w/4 - a, y-h/2-h/4);
// DRAW BUTTERFLY'S RIGHT WING
for (int i = 0 ; i < X.length ; i++)
iX[i] = x + (int)(w * (.03 + s * X[i]));
g.setColor(fgColor[n]);
g.fillPolygon(iX, iY, X.length);
g.setColor(Color.black);
g.drawPolygon(iX, iY, X.length);
// DRAW BUTTERFLY'S LEFT WING
for (int i = 0 ; i < X.length ; i++)
iX[i] = x + (int)(w * (-.03 - s * X[i]));
g.setColor(fgColor[n]);
g.fillPolygon(iX, iY, X.length);
g.setColor(Color.black);
g.drawPolygon(iX, iY, X.length);
// DRAW SPOTS ON WINGS
g.setColor(bgColor);
int sw = (int)(s * w);
g.fillOval(x+w/33 + sw/4 , y - h/3, sw/2,h/4);
g.fillOval(x-w/33 - 3*sw/4+1, y - h/3, sw/2,h/4);
g.fillOval(x+w/33 + sw/5 , y , sw/3,h/3);
g.fillOval(x-w/33 - 3*sw/5+1, y , sw/3,h/3);
}
// USER CALLBACK TO MONITOR MOUSE POSITION
public boolean mouseMove(Event e, int x, int y) {
rate = .1 + Math.max(0, Math.min(.9, .9 * x / width)); // MOUSE X CONTROLS FLAP RATE
var = Math.max(0, Math.min(1, 1. * y / height)); // MOUSE Y CONTROLS RANDOMNESS
return true;
}
}