This is an example of a multithreaded Java applet, with source. Click in the applet area below to start a ball bouncing. Each time you click the mouse below, it starts another thread bouncing another ball, whose color, diameter, velocity, and direction are random.
I wrote this for a class, but because it's kind of a fun, I thought people might appreciate seeing how to write such an applet.
Click here to go back to my main page.
Here's the source. When you figure out how to make a successful
IPO based on this code :-),
feel free to throw a few thousand shares my way.
// This applet waits for the user to click the mouse. When the mouse is clicked,
// it starts a thread that bounces a ball around the inside edges of the applet's
// displayable area. Each time you click the mouse, the applet starts a new
// thread that randomly picks the color of the ball, and starts bouncing it.
//
// How does it do this? Well, an example would have been nice. But it looks
// like the proper way to do this is to define a JPanel that contains the image
// of bouncing balls. Then, we pick a starting point for the ball (picked at
// random). Then we randomly pick a velocity (x and y change). Then the
// JPanel's paintComponent paints the rectangle its background color and
// draws the ball.
//
// For the first ball this is easy; you just draw the ball on the background. The
// second time you redraw the background, move the starting point by velocity,
// and draw the ball again. (If the starting point plus velocity puts the ball
// outside the bounds of the JPanel, however, you have to reflect the ball
// back again. How am I going to do this? I don't know yet.)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
import java.net.*;
public class PongOnSpeed extends JApplet implements MouseListener, Runnable
{
// Maximum speed the ball can move.
private final int MAX_SPEED = 200;
// Dimensions of the panel on which we bounce the balls.
Dimension panelDimensions;
// How many balls are we juggling simultaneously?
final private static int MAX_BALL_COUNT = 40;
int ballCount;
private Thread[] ballThreads = new Thread[MAX_BALL_COUNT];
Graphics g;
JPanel panel;
// What direction and speed does the ball move?
Dimension[] vector = new Dimension[MAX_BALL_COUNT];
// Where does the ball get displayed next?
Dimension[] next = new Dimension[MAX_BALL_COUNT];
// What color is the ball?
private Color[] color = new Color[MAX_BALL_COUNT];
// What is the name of this thread?
private String[] name = new String[MAX_BALL_COUNT];
// Diameter of the ball?
private int[] diameter = new int[MAX_BALL_COUNT];
public void init ()
{
ballCount = 0;
Container contentPane = getContentPane();
// Add a JPanel to the contentPane of the applet.
JPanel panel = new JPanel();
panel.setOpaque(true);
contentPane.add(panel);
// Get the dimensions so that we know where to start bouncing
// balls when they hit the edges.
panelDimensions = getSize();
// We start with zero balls in the air.
ballCount = 0;
// This lets us known when the user has hit the mouse button.
addMouseListener(this);
}
public void start ()
{
for(int i = 0; i < ballThreads.length; i++)
if(ballThreads[i] != null)
ballThreads[i].start();
}
public void stop ()
{
// Kill all the threads currently running.
for(int i = 0; i < ballThreads.length; i++)
ballThreads[i] = null;
}
public void mousePressed (MouseEvent e)
{
// Each time we get a mouse button pressed event, we need to
// start a ball thread to create a ball and start it running.
if(ballCount < MAX_BALL_COUNT)
{
int width = (int)panelDimensions.getWidth();
int height = (int)panelDimensions.getHeight();
// Calculate a random direction and speed.
vector[ballCount] =
new Dimension((int)((Math.random() * MAX_SPEED) - (MAX_SPEED/2)),
(int)((Math.random() * MAX_SPEED) - (MAX_SPEED/2)));
color[ballCount] = randomColor();
// Select a random location for the ball.
next[ballCount] = new Dimension((int)(Math.random() * panelDimensions.getWidth()),
(int)(Math.random() * panelDimensions.getHeight()));
// Pick a random diameter.
diameter[ballCount] = Math.max(20, (int)(Math.random() * 40));
ballThreads[ballCount] = new Thread(this);
ballThreads[ballCount].start();
ballCount++;
}
}
public Color randomColor ()
{
return(new Color((int)(Math.max(10, Math.random()*255)),
(int)(Math.max(10, Math.random()*255)),
(int)(Math.max(10, Math.random()*255))));
}
public void run ()
{
// Find out which is the current Thread we are running.
Thread currentThread = Thread.currentThread();
// Get the index number of this thread.
int index = getIndex(currentThread);
while(ballThreads[index] == currentThread)
{
repaint();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e) {};
}
}
private int getIndex (Thread current)
{
for(int i = 0; i < ballThreads.length; i++)
if(current == ballThreads[i])
return(i);
return(-1);
}
public void mouseClicked (MouseEvent e)
{
}
public void mouseReleased (MouseEvent e)
{
}
public void mouseExited (MouseEvent e)
{
}
public void mouseEntered (MouseEvent e)
{
}
public void paint (Graphics g)
{
// Find out which is the current Thread we are running.
for(int index = 0; index < ballThreads.length; index++)
{
if(ballThreads[index] != null)
{
if(index == 0)
{
// Set the background color.
g.setColor(Color.black);
g.fillRect(0, 0, (int)panelDimensions.getWidth(),
(int)panelDimensions.getHeight());
}
g.setColor(color[index]);
// Draw the ball at the next location.
g.fillOval((int)next[index].getWidth(),
(int)next[index].getHeight(), diameter[index],
diameter[index]);
repaint();
// Now move the ball.
// See if the ball's next location is outside the boundaries of the JPanel or not.
int nextX = (int)(next[index].getWidth() + vector[index].getWidth());
int vectorX = (int)vector[index].getWidth();
// See if the X coordinate moves us off the visible area to the left.
// If so, we have to bounce back in by inverting the sign of the
// X part of vector.
if((nextX < 0) || ((nextX + diameter[index]) > panelDimensions.getWidth()))
{
vectorX = (int)(-vector[index].getWidth());
nextX = (int)next[index].getWidth() + vectorX;
}
// See if the Y coordinate moves us off the visible area to the left.
// If so, we have to bounce back in by inverting the sign of the
// Y part of vector.
int nextY = (int)(next[index].getHeight() + vector[index].getHeight());
int vectorY = (int)vector[index].getHeight();
if((nextY < 0) || ((nextY + diameter[index]) > panelDimensions.getHeight()))
{
vectorY = (int)(-vector[index].getHeight());
nextY = (int)next[index].getHeight() + vectorY;
}
// Save the new values for direction.
vector[index] = new Dimension(vectorX, vectorY);
// New position for the ball.
next[index] = new Dimension(nextX, nextY);
try
{
Thread.sleep(100/ballCount);
}
catch (InterruptedException e) {};
}
}
}
}
Click here to go back to my
main page.