Pong On Speed Applet

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.

If this was helpful,  PayPal users can contribute here:
// 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.