/* * @(#)Juggling.java 1.0 95/05/01 Chris Seguin * E-mail: seguin@uiuc.edu * * Copyright (c) 1995 University of Illinois (UIUC) * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and without * fee is hereby granted provided that this copyright notice * appears in all copies. * * I MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. UIUC SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. * * To be fair, I used code created by James Gosling and extended it * to juggle objects, rather than just animate a gif image. * */ import java.io.InputStream; import awt.*; import browser.*; import net.www.html.*; /** * JugglingImages class. This is a container for a list * of images that are animated. * * @author Chris Seguin * @version 1.0, May 1, 1995 */ class JugglingImages { /** * The images. */ Image imgs[]; /** * The number of images actually loaded. */ int nimgs = 0; /** * Load the images, from dir. The images are assumed to be * named T1.gif, T2.gif... * Once all images are loaded the applet is resized to the * maximum width and height. */ JugglingImages(URL context, String dir, Juggling parent, int maxWidth, int maxHeight) { imgs = new Image[40]; for (int i = 1; i < imgs.length; i++) { Image im = parent.getImage(dir + "/T" + i + ".gif"); if (im == null) { break; } imgs[nimgs++] = im; if (im.width > maxWidth) { maxWidth = im.width; } if (im.height > maxHeight) { maxHeight = im.height; } } parent.resize(maxWidth, maxHeight); } } /** * BallPaths class. This is a container for a paths * of juggling balls * * @author Chris Seguin * @version 1.0, May 1, 1995 */ class BallPaths { /** * Arrays containing the path of the balls */ int pnX[] = {0}; int pnY[] = {0}; int nLength = 1; /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex) { if ((nIndex > nLength) || (nIndex < 0)) return 0; return pnX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex > nLength) || (nIndex < 0)) return 0; return pnY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * CascadeBallPaths class. This is a container for a paths * of juggling balls, the balls are moving in a standard * cascade pattern * * @author Chris Seguin * @version 1.0, May 1, 1995 */ class CascadeBallPaths extends BallPaths { /** * Arrays containing the path of the balls */ int pnX[] = { 20, 24, 27, 31, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 143, 144, 141, 138, 134, 130, 126, 123, 119, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 7, 6, 9, 12, 16 }; int pnY[] = { 76, 78, 76, 70, 60, 60, 50, 42, 34, 28, 22, 18, 14, 12, 10, 10, 10, 12, 14, 18, 22, 28, 34, 42, 50, 66, 68, 70, 72, 74, 76, 78, 76, 70, 60, 60, 50, 42, 34, 28, 22, 18, 14, 12, 10, 10, 10, 12, 14, 18, 22, 28, 34, 42, 50, 66, 68, 70, 72, 74 }; /** * The length of the arrays */ int nLength = 60; /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * ReverseCascadeBallPaths class. This is a container * for a paths of juggling balls, the balls are moving * in a reverse cascade pattern * * @author Chris Seguin * @version 1.0, May 1, 1995 */ class ReverseCascadeBallPaths extends BallPaths { /** * Arrays containing the path of the balls */ int pnX[] = { 12, 9, 6, 3, 0, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 125, 120, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 27, 24, 21, 18, 15 }; int pnY[] = { 60, 60, 60, 60, 60, 60, 51, 42, 35, 28, 23, 18, 15, 12, 11, 10, 11, 12, 15, 18, 23, 28, 35, 42, 51, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 51, 42, 35, 28, 23, 18, 15, 12, 11, 10, 11, 12, 15, 18, 23, 28, 35, 42, 51, 60, 60, 60, 60, 60 }; /** * The length of the arrays */ int nLength = 60; /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; return pnY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * JugglingBall class. This is a juggling ball * * @author Chris Seguin * @version 1.0, May 1, 1995 */ class JugglingBall { /** * The location on the ball's path */ int nCycleSlot; /** * The color of the ball - specified by an index into the ball array */ int nBallColor; /** * The current location of the ball */ int nX; int nY; /** * The path to follow */ BallPaths ptbpPath; /** * JugglingBall - creates a juggling ball */ public JugglingBall (int nStartPos, int nStartColor, BallPaths ptbpThePath) { nCycleSlot = nStartPos; nBallColor = nStartColor; ptbpPath = ptbpThePath; nX = ptbpPath.LookupX(nStartPos); nY = ptbpPath.LookupY(nStartPos); } /** * Move - moves the ball to the next location */ public void Move () { nCycleSlot++; if ((nCycleSlot >= ptbpPath.Length ()) || (nCycleSlot <= 0)) { nCycleSlot = 0; } nX = ptbpPath.LookupX(nCycleSlot); nY = ptbpPath.LookupY(nCycleSlot); //System.out.println ("Move (" + nX + ", " + nY + ") ===> " + nCycleSlot); } /** * XLoc - returns the x location */ public int XLoc () { return nX; } /** * YLoc - returns the Y location */ public int YLoc () { return nY; } /** * Color - returns the color */ public int Color () { return nBallColor; } } /** * HandPath class. This is a container for the paths of the hands * * @author Chris Seguin * @version 1.0, May 3, 1995 */ class HandPath { /** * Arrays containing the path of the hands */ int pnLeftHandX[] = { 7, 6, 9, 12, 16, 20, 24, 27, 31, 35, 35, 31, 27, 24, 20, 16, 12, 9, 6, 7 }; int pnRightHandX[] = { 143, 144, 141, 138, 134, 130, 126, 123, 119, 115, 115, 119, 123, 126, 130, 134, 138, 141, 144, 143 }; int pnHandY[] = { 73, 75, 77, 79, 81, 83, 85, 83, 77, 67, 67, 57, 51, 49, 51, 53, 55, 57, 59, 61 }; /** * The length of the arrays */ int nLength = 60; int nBalls = 0; /** * HandPath - creates a hand path */ public HandPath (int nStartBalls) { nBalls = nStartBalls; } /** * LookupX - looks up the appropriate value of X */ public int LookupX (int nIndex, boolean bLeft) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; // Limit the lookup to the range if (nIndex >= 20 * nBalls) nIndex = 19; while (nIndex >= 20) nIndex -= 20; // Look up the value if (bLeft) return pnLeftHandX[nIndex]; else return pnRightHandX[nIndex]; } /** * LookupY - looks up the appropriate value of Y */ public int LookupY (int nIndex) { if ((nIndex >= nLength) || (nIndex < 0)) return 0; // Limit the lookup to the range if (nIndex >= 20 * nBalls) nIndex = 19; while (nIndex >= 20) nIndex -= 20; // Look up the value return pnHandY[nIndex]; } /** * Length - the number of data points stored in the path */ public int Length () { return nLength; } } /** * Hand class. This is a hand * * @author Chris Seguin * @version 1.0, May 3, 1995 */ class Hand { /** * The location on the ball's path */ int nCycleSlot; /** * Whether this is the left hand */ boolean bLeft; /** * The current location of the ball */ int nX; int nY; /** * The path to follow */ HandPath phPath; /** * Hand - creates a hand */ public Hand (int nStartPos, HandPath phThePath, boolean bStartLeft) { nCycleSlot = nStartPos; bLeft = bStartLeft; phPath = phThePath; nX = phPath.LookupX(nStartPos, bLeft); nY = phPath.LookupY(nStartPos); } /** * Move - moves the ball to the next location */ public void Move () { nCycleSlot++; if ((nCycleSlot >= phPath.Length ()) || (nCycleSlot <= 0)) { nCycleSlot = 0; } nX = phPath.LookupX(nCycleSlot, bLeft); nY = phPath.LookupY(nCycleSlot); //System.out.println ("Move (" + nX + ", " + nY + ") ===> " + nCycleSlot); } /** * XLoc - returns the x location */ public int XLoc () { return nX; } /** * YLoc - returns the Y location */ public int YLoc () { return nY; } } /** * A juggling demonstration program * * @author Chris Seguin * @version 1.0, May 1, 1995 */ public class Juggling extends Applet implements Runnable { /** * The path of the juggling balls */ BallPaths pjbPaths; /** * The juggling balls */ JugglingBall pjbBalls[] = {null, null, null}; /** * The paths that the hands trace out */ HandPath phHandPaths; /** * The hands */ Hand phLeft; Hand phRight; /** * The directory or URL from which the images are loaded */ String dir; /** * The images used. */ JugglingImages jbiImages; /** * The thread animating the images. */ Thread kicker = null; /** * The speed at which the icon changes */ int nSpeed; /** * Shape of the window */ int nHeight = 0; int nWidth = 0; /** * The number of balls in the demonstration */ int nBalls = 0; /** * Loop variable - used everywhere */ int ndx = 0; /** * Initialize the applet. Get attributes. */ public void init() { String at = getAttribute("img"); dir = (at != null) ? at : "doc:/demo/images/duke"; at = getAttribute("speed"); nSpeed = (at!= null) ? Integer.valueOf (at).intValue() : 20; at = getAttribute("height"); nHeight = (at!= null) ? Integer.valueOf (at).intValue() : 100; at = getAttribute("width"); nWidth = (at!= null) ? Integer.valueOf (at).intValue() : 160; at = getAttribute("balls"); nBalls = (at!= null) ? Integer.valueOf (at).intValue() : 3; pjbPaths = new CascadeBallPaths (); pjbBalls[0] = new JugglingBall ( 0, 0, pjbPaths); pjbBalls[1] = new JugglingBall (40, 2, pjbPaths); pjbBalls[2] = new JugglingBall (20, 4, pjbPaths); phHandPaths = new HandPath (nBalls); phLeft = new Hand (5, phHandPaths, true); phRight = new Hand (35, phHandPaths, false); } /** * Run the image loop. This methods is called by class Thread. * @see java.lang.Thread */ public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); jbiImages = new JugglingImages(documentURL, dir, this, nWidth, nHeight); while (width > 0 && height > 0 && kicker != null) { ndx = 0; for (ndx = 0; ndx < nBalls; ndx++) { (pjbBalls[ndx]).Move(); } phLeft.Move(); phRight.Move(); repaint(); Thread.sleep(nSpeed); } } /** * Paint the current frame. */ public void paint(Graphics g) { if ((jbiImages != null) && (jbiImages.imgs != null)) { ndx = 0; for (ndx = 0; ndx < nBalls; ndx++) { g.drawImage(jbiImages.imgs[pjbBalls[ndx].Color()], (pjbBalls[ndx]).XLoc(), (pjbBalls[ndx]).YLoc()); } // Draw the hands g.drawImage(jbiImages.imgs[7], phLeft.XLoc(), phLeft.YLoc()); g.drawImage(jbiImages.imgs[7], phRight.XLoc(), phRight.YLoc()); } } /** * Start the applet by forking an animation thread. */ public void start() { if (kicker == null) { kicker = new Thread(this); kicker.start(); } } /** * Stop the applet. The thread will exit because kicker is set to null. */ public void stop() { kicker = null; } }