/****************************/
/* Bouncing Balls V2.0 1997 */
/* for Java API 1.1.3 */
/****************************/
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
public class bounce extends Applet implements Runnable, KeyListener,
MouseListener, MouseMotionListener, ActionListener, ItemListener
{
// image for double-buffering.
Image backBuffer,newbackBuffer;
// graphics context of double-buffering.
Graphics backBufferG,newbackBufferG;
// overload interface Runnable's run()
Thread animator;
Button north,Gravity,Velocity, Restart;
Checkbox checkbox;
TextField T_Gravity, T_Velocity;
Panel south, east;
Choice choice;
Color Background_Color=Color.white,Border_Color=Color.black;
Image girl_img[],gold;
double gravity = 300.0;
double radius = 6.0;
double velocity = 300.0;
// in ms, for each frame of animation
int delay = 100;
// geometry of the animation box
int Box_Width=200,Box_Height=200,bx,by;
// list of past trajectories for grabbed ball
int stacklength=50, ip=-1, ip_omit=5;
long last_time[] = new long [stacklength];
double last_x[] = new double [stacklength];
double last_y[] = new double [stacklength];
int girl_x_stacklength=10, girl_x_ip=0;
double girl_saved_x[] = new double [girl_x_stacklength];
boolean one_round=false,pause=false,mute=true,first_time=true;
boolean up=false,left=false,right=false,dead=false,gamestart=false;
int total_ball_no = 3; // total number of balls
int ball_no=1; // number of balls in displaying
int min_ball=0; // which ball is caught bu mouce
String S_ball_no; // parameter get from Choice
Ball[] ball= {new Ball(), new Ball(), new Ball()};
int girl_no = 6; // number of images for girl
int girl_cur=0, score=0, score_old=1;
// index for which girl_img is currently on screen
// 0--stand, 1--left, 2--right, 3--down, 4--up, 5--dead.
double girl_x,girl_y,gold_x,gold_y,gold_width,gold_height;
double girl_width[], girl_height[];
double girl_rep_x[]=new double[5],girl_rep_y[]=new double[5];
double girl_vx=0.,girl_vy=0.,girl_initial_vy=0.,girl_x_increment=1.;
// double girl_timescale=100*1E-3,tmp;
// peacetime is the time in seconds after start
// that girl can move around without jeopardy.
double program_start, run_start, peacetime=1., tmp;
Font myfont = new Font("TimesRoman",Font.PLAIN,14);
Beeper simplebeeper = new Beeper();
public void init()
{
String arg;
int i;
// get parameters from applet tag fields
arg = getParameter("delay");
if (arg != null) delay = Integer.parseInt(arg);
arg = getParameter("Box_Width");
if (arg != null) Box_Width = Integer.parseInt(arg);
arg = getParameter("Box_Height");
if (arg != null) Box_Height = Integer.parseInt(arg);
arg = getParameter("gravity");
if (arg != null) gravity = (Double.valueOf(arg)).doubleValue();
arg = getParameter("radius");
if (arg != null) radius = (Double.valueOf(arg)).doubleValue();
arg = getParameter("velocity");
if (arg != null) velocity = (Double.valueOf(arg)).doubleValue();
arg = getParameter("peacetime");
if (arg != null) peacetime = (Double.valueOf(arg)).doubleValue();
arg = getParameter("girl_x_increment");
if (arg != null) girl_x_increment=(Double.valueOf(arg)).doubleValue();
arg = getParameter("girl_initial_vy");
if (arg != null) girl_initial_vy=(Double.valueOf(arg)).doubleValue();
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
enableEvents(AWTEvent.KEY_EVENT_MASK);
setLayout(new BorderLayout());
// North source lists
add ("North",north=new Button("Click to see source for this applet"));
north.addActionListener(this);
north.addKeyListener(this);
north.setActionCommand("Show source");
// South Buttons and TextFields
Panel south = new Panel();
add ("South", south);
south.setLayout(new FlowLayout());
south.add(Gravity = new Button ("Change g"));
Gravity.addActionListener(this);
Gravity.addKeyListener(this);
Gravity.setActionCommand("Change g");
south.add(T_Gravity = new TextField
(Integer.toString((int)gravity,10), 4));
T_Gravity.addKeyListener(this);
south.add(Velocity = new Button ("Change v"));
Velocity.addActionListener(this);
Velocity.addKeyListener(this);
Velocity.setActionCommand("Change v");
south.add(T_Velocity = new TextField
(Integer.toString((int)velocity,10), 4));
T_Velocity.addKeyListener(this);
// East Checkbox
Panel east= new Panel();
add ("East", east);
east.setLayout(new GridLayout(3,1));
choice = new Choice();
choice.addItem("One");
choice.addItem("Two");
choice.addItem("Three");
east.add(choice);
choice.addKeyListener(this);
choice.addItemListener(this);
// choice.enableEvents(AWTEvent.KEY_EVENT_MASK);
checkbox = new Checkbox("Mute",null,true);
east.add(checkbox);
checkbox.addKeyListener(this);
checkbox.addItemListener(this);
east.add(Restart = new Button ("Restart"));
Restart.addKeyListener(this);
Restart.addActionListener(this);
Restart.setActionCommand("Restart");
// Center animation box
bx = getBounds().x+(getSize().width-Box_Width)/3;
by = getBounds().y+(getSize().height-Box_Height)/2;
for ( i=0; i< total_ball_no; i++)
{
String fillin_color;
ball[i].radius = radius;
ball[i].x = ball[i].radius +
(Box_Width-2*ball[i].radius)*Math.random();
ball[i].y = ball[i].radius +
(Box_Height-2*ball[i].radius)*Math.random();
// Initialize balls
tmp = Math.random() * Math.PI * 2.;
ball[i].vx = velocity*Math.cos(tmp);
ball[i].vy = velocity*Math.sin(tmp);
fillin_color = getParameter("Ball_Fillin_Color");
ball[i].Fillin_Color =
ball[i].colorFromString(fillin_color,Color.black);
ball[i].Fillin_Color = Color.black;
}
arg = getParameter("Background_Color");
Background_Color = ball[0].colorFromString (arg,Color.white);
setBackground(Background_Color);
setBackground(Color.white);
arg = getParameter("Border_Color");
Border_Color = ball[0].colorFromString (arg,Color.black);
Border_Color = Color.black;
// Create double buffer with getSize of the animation box
backBuffer = createImage(Box_Width+1,Box_Height+1);
backBufferG = backBuffer.getGraphics();
//load resource images for gold
gold = getImage (getCodeBase(),
"Images/mygold_small.xbm");
//load resource images for running girl
girl_img = new Image[girl_no];
girl_width = new double[girl_no];
girl_height = new double[girl_no];
for (i=0;i Box_Width-ball[min_ball].radius)
ball[min_ball].x =Box_Width-ball[min_ball].radius;
if (ball[min_ball].y < ball[min_ball].radius)
ball[min_ball].y = ball[min_ball].radius;
if (ball[min_ball].y > Box_Height-ball[min_ball].radius)
ball[min_ball].y = Box_Height-ball[min_ball].radius;
getAppletContext().showStatus
(ball[min_ball].x+" "+ball[min_ball].y+" ball grabbed");
repaint();
return;
}
return;
}
public void mouseDragged(MouseEvent evt)
{
int x=evt.getX(), y=evt.getY();
if (!dead)
{
ball[min_ball].x = x - bx;
ball[min_ball].y = y - by;
if (ball[min_ball].x < ball[min_ball].radius)
ball[min_ball].x = ball[min_ball].radius;
if (ball[min_ball].x > Box_Width-ball[min_ball].radius)
ball[min_ball].x = Box_Width-ball[min_ball].radius;
if (ball[min_ball].y < ball[min_ball].radius)
ball[min_ball].y = ball[min_ball].radius;
if (ball[min_ball].y > Box_Height-ball[min_ball].radius)
ball[min_ball].y = Box_Height-ball[min_ball].radius;
getAppletContext().showStatus
(ball[min_ball].x+" "+ball[min_ball].y+" ball dragged");
// save the dragged trajectory in a stack which goes around:
ip ++;
if (ip == stacklength)
{
ip -= stacklength;
one_round = true;
}
last_time[ip] = System.currentTimeMillis();
last_x[ip] = ball[min_ball].x;
last_y[ip] = ball[min_ball].y;
repaint();
return;
}
return;
}
public void mouseReleased(MouseEvent evt)
{
int x=evt.getX(),y=evt.getY();
if(!dead)
{
// take a segment of the trajectory to estimate the ball velocity
int first_ip,last_ip;
last_ip=(ip>ip_omit)?(ip-ip_omit):ip;
if (one_round)
{
first_ip = ip + 1 ;
if (first_ip == stacklength) first_ip = 0;
}
else first_ip = 0;
// position still like being dragged
ball[min_ball].x = x - bx;
ball[min_ball].y = y - by;
if (ball[min_ball].x < ball[min_ball].radius)
ball[min_ball].x = ball[min_ball].radius;
if (ball[min_ball].x > Box_Width-ball[min_ball].radius)
ball[min_ball].x = Box_Width-ball[min_ball].radius;
if (ball[min_ball].y < ball[min_ball].radius)
ball[min_ball].y = ball[min_ball].radius;
if (ball[min_ball].y > Box_Height-ball[min_ball].radius)
ball[min_ball].y = Box_Height-ball[min_ball].radius;
// velocity estimate:
if (last_ip > first_ip)
{
long t_del = last_time[last_ip] - last_time[first_ip];
ball[min_ball].vx =
(last_x[last_ip]-last_x[first_ip])/(double)t_del*1E+3;
ball[min_ball].vy =
(last_y[last_ip]-last_y[first_ip])/(double)t_del*1E+3;
}
// clear the stack
ip = -1; one_round = false;
if (!pause)
print_press_p_to_pause();
return;
}
return;
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void keyTyped (KeyEvent e) {
// System.out.println("haha!");
}
public void keyPressed (KeyEvent e)
{
int i;
switch(e.getKeyCode())
{
case 'p':
case 'P':
pause = (pause != true);
if (pause)
{
getAppletContext().showStatus("Paused: press p to restart");
animator.suspend();
}
else
{
if (!pause)
{
print_press_p_to_pause();
animator.resume();
}
}
return;
case KeyEvent.VK_LEFT:
case 'J':
case 'j':
{
if (up) return;
girl_cur = 1;
left = true;
girl_x -= girl_x_increment;
if ( girl_x <= 0. )
{
girl_x = 0.;
if (!mute) simplebeeper.beep();
}
set_rep_coord();
return;
}
case KeyEvent.VK_RIGHT:
case 'L':
case 'l':
{
if (up) return;
girl_cur = 2;
right = true;
girl_x += girl_x_increment;
if ( girl_x >= Box_Width - girl_width[girl_cur] )
{
girl_x = Box_Width - girl_width[girl_cur];
if (!mute) simplebeeper.beep();
}
set_rep_coord();
return;
}
case KeyEvent.VK_DOWN:
case 'M':
case 'm':
{
if (up) return;
girl_cur = 3;
girl_y = Box_Height - girl_height[girl_cur];
set_rep_coord();
return;
}
case KeyEvent.VK_UP:
case 'K':
case 'k':
{
if (up) return;
girl_cur = 4;
up = true;
girl_vy = -girl_initial_vy;
i = girl_x_ip+1;
if (i==girl_x_stacklength) i=0;
girl_vx = (girl_saved_x[girl_x_ip]-girl_saved_x[i])/
(girl_x_stacklength*delay*(1E-3))*0.6;
set_rep_coord();
return;
}
default: return;
}
}
public void set_rep_coord()
{
// upper-left corner
girl_rep_x[0] = girl_x;
girl_rep_y[0] = girl_y;
// upper-right corner
girl_rep_x[1] = girl_x+girl_width[girl_cur];
girl_rep_y[1] = girl_y;
// lower-left corner
girl_rep_x[2] = girl_x;
girl_rep_y[2] = girl_y+girl_height[girl_cur];
// lower-right corner
girl_rep_x[3] = girl_x+girl_width[girl_cur];
girl_rep_y[3] = girl_y+girl_height[girl_cur];
// center
girl_rep_x[4] = girl_x+girl_width[girl_cur]/2.;
girl_rep_y[4] = girl_y+girl_height[girl_cur]/2.;
}
public int which_ball_hit_girl()
{
double dis2;
int i,irep;
for (i=0;i= xmax)
{
if (!mute) simplebeeper.beep();
ball[i].x = 2*xmax - ball[i].x;
ball[i].vx = - ball[i].vx;
}
if (ball[i].y <= ymin)
{
if (!mute) simplebeeper.beep();
if (gravity == 0.)
{
ball[i].y = 2*ymin - ball[i].y;
ball[i].vy = - ball[i].vy;
}
else
{
y_old = ball[i].y - delay*(1E-3)*(ball[i].vy+vy_old[i])/2.;
if (ymin - y_old < 0)
{
tc = (-vy_old[i]-Math.sqrt(vy_old[i]*vy_old[i]+
2*gravity*(ymin-y_old)))/gravity;
vy_c = vy_old[i] + tc * gravity;
ball[i].vy = -vy_c + (delay*(1E-3)-tc) * gravity;
}
else
{
tc = 0.;
vy_c = 0.;
ball[i].vy = 0.;
}
// ignore all multiple collisions, avoid singularity at vy = 0.
if (ball[i].vy < 0.0001)
{
ball[i].vy = 0.;
ball[i].y = ymin;
}
else ball[i].y = ymin+(-vy_c+ball[i].vy)*(delay*(1E-3)-tc)/2.;
if (vy_c<-2.)
if (!mute) play(getDocumentBase(), getParameter("thump"));
}
}
if (ball[i].y >= ymax)
{
if (gravity == 0)
{
ball[i].y = 2*ymax - ball[i].y;
ball[i].vy = - ball[i].vy;
}
else
{
y_old = ball[i].y-delay*(1E-3)*(ball[i].vy+vy_old[i])/2.;
if (ymax-y_old > 0)
{
tc = (-vy_old[i]+Math.sqrt(vy_old[i]*vy_old[i]+
2*gravity*(ymax-y_old)))/gravity;
vy_c = vy_old[i] + tc * gravity;
ball[i].vy = -vy_c + (delay*(1E-3)-tc) * gravity;
}
else
{
tc = 0.;
vy_c = 0.;
ball[i].vy = 0.;
}
// ignore all multiple collisions, avoid singularity at vy = 0.
if (ball[i].vy > -0.0001)
{
ball[i].vy = 0.;
ball[i].y = ymax;
}
else ball[i].y = ymax + (-vy_c+ball[i].vy)*(delay*(1E-3)-tc)/2.;
if (vy_c>2.)
if (!mute) play(getDocumentBase(), getParameter("thump"));
}
}
repaint();
}
// if girl has jumped:
if (up)
{
girl_vy_old = girl_vy;
girl_vy += delay*(1E-3)*gravity*2.0;
girl_y += delay*(1E-3)*(girl_vy+girl_vy_old)/2.;
girl_x += delay*(1E-3)*girl_vx;
}
if (girl_y < 2)
{
girl_y = 2.;
girl_vy = 0.;
}
if (girl_y > Box_Height-girl_height[girl_cur])
{
girl_cur = 0;
set_rep_coord();
girl_y = Box_Height-girl_height[girl_cur];
girl_vy = 0.;
up = false;
}
if (!gamestart) gamestart =
(System.currentTimeMillis()-run_start)/1000.>peacetime;
if (girl_x > Box_Width - girl_width[girl_cur])
girl_x = Box_Width - girl_width[girl_cur];
if (girl_x < 2)
girl_x = 2.;
girl_between_x = ((girl_x>gold_x) && (girl_xgold_x) &&
(girl_x+girl_width[girl_cur]gold_y) && (girl_ygold_y) &&
(girl_y+girl_height[girl_cur]girl_x) && (gold_xgirl_x) && (gold_x+gold_widthgirl_y) && (gold_ygirl_y) && (gold_y+gold_height Box_Height-girl_height[girl_cur])
girl_y = Box_Height-girl_height[girl_cur];
dead = true;
repaint();
animator.suspend();
}
}
repaint();
}
public void print_press_p_to_pause()
{
int i;
double bit_in_second = 1.;
if ((System.currentTimeMillis()-run_start)/1000. < peacetime)
{
String bits_from_run = "get ready"; // show time as dots ...
for (i=1;i<=Math.round((peacetime-(System.currentTimeMillis()-run_start)/1000.)
/bit_in_second);i++)
bits_from_run = bits_from_run + ".";
getAppletContext().showStatus(bits_from_run+" (press p to pause)");
}
else getAppletContext().showStatus("press p to pause");
}
public String getAppletInfo()
{
return "Ju Li 1997 ";
}
String[][] parameterInfo = {
{"source","String","java source code URL"},
{"velocity","double","initial velocity of the ball, in screen pixel/second"},
{"gravity","double","gravity acceleration, in screen pixel/second^2"},
{"delay","int","time inteval of animation in millisecond"},
{"radius","double","radius of the ball, in screen pixels"},
{"Box_Width","int","width of the animation box"},
{"Box_Height","int","height of the animation box"},
{"Ball_Fillin_Color","String",
"RGB format like FF0000, or red,green,blue,white,black,gray"},
{"Background_Color","String",
"RGB format like FF0000, or red,green,blue,white,black,gray"},
{"Border_Color","String",
"RGB format like FF0000, or red,green,blue,white,black,gray"},
};
public String[][] getParameterInfo() {
return parameterInfo;
}
}