// Java class to produce animated Bloxed logo with pieces falling into place. // Version 1.00, April 10 1997. // Version 1.01, April 3 1998: Made delay final static. // Copyright 1997 Steven Singer, all rights reserved. // This program may not be distributed without prior authorisation from the // author, however, permision is granted to download and view this program. // This is my first ever Java prgram, so I don't recommend using it as a // template for other programs. Some of the code was taken from example // programs given in The Java Tutorial by Mary Campione and Kathy Walrath. // Known bugs: // // On some implementations of Java (MSIE springs to mind), the individual // piece images held in block[] aren't correctly generated from the image // loaded into blocks before the animation starts. This shows up as the first // few dropped pieces being plain, rather than having block images on them. // This has all the hallmarks of the generating code and/or the animation code // being run before the main image has finished loading. I thought the media // tracker was meant to take care of all this - obviously I'm missing // something somewhere. I can't debug this problem as it doesn't show under // Netscape 3.0 or Appletviewer - the two Java interpreters I have access to. // // The animation isn't quite as smooth as it could be (again this is // interpreter dependent). import java.applet.Applet; import java.awt.Graphics; import java.awt.Color; import java.awt.Image; import java.awt.image.*; import java.awt.Event; import java.awt.Rectangle; import java.awt.MediaTracker; public class Bloxed extends Applet implements Runnable { final static byte x[] = { 0, 0, 2, 2, 2, 2, 5, 5, 7, 10, 9, 11, 10, 14, 16, 15, 14, 16, 19, 19, 19, 19, 22, 22, 24, 25, 24}; final static byte y[] = { 9, 5, 9, 7, 5, 3, 9, 5, 9, 9, 7, 7, 3, 9, 9, 6, 4, 4, 9, 7, 5, 3, 9, 5, 9, 7, 3}; final static byte c[] = { 0, 0, 4, 5, 4, 5, 0, 0, 6, 3, 0, 0, 3, 1, 2, 6, 2, 1, 1, 2, 1, 2, 0, 0, 4, 0, 5}; final static byte s[] = { 0, 0, 9, 10, 9, 10, 0, 0, 11, 7, 0, 0, 8, 1, 6, 11, 5, 3, 2, 4, 2, 4, 0, 0, 9, 0, 10}; final static byte coords[] = { 0, 0, 0, 1, 0, 2, 0, 3, -1, 0, -1, 1, -1, 2, 0, 2, 1, 0, 0, 0, -1, 0, -1, 1, -1, 0, 0, 0, 0, 1, 0, 2, -1, 0, -1, 1, 0, 1, 1, 1, 0, 0, -1, 0, -1, 1, -1, 2, 0, 0, 0, 1, 0, 2, -1, 2, 0, 0, -1, 1, 0, 1, 1, 1, -1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, 1, 1, 1, -1, 1, 0, 1, 0, 0, 1, 0, -1, 0, 0, 0, -1, 1, 0, 1}; int shape = -1; int pos; final static int delay = 20; Thread animatorThread; boolean frozen = false; Image[] block; Image blocks; MediaTracker tracker; public void init() { // All the images are held in one gif image. We separate them out later. // We use a media tracker to ensure that we don't start animating till the // load has finished. tracker = new MediaTracker(this); block = new Image[7]; blocks = getImage(getCodeBase(),"blocks.gif"); tracker.addImage(blocks, 0); for(int i=0; i<7; i++) block[i] = createImage(16,16); } public void start() { if (frozen) { //Do nothing. The user has requested that we stop changing the image. } else { //Start animating! if (animatorThread == null) { animatorThread = new Thread(this); } animatorThread.start(); } } public void stop() { //Stop the animating thread. animatorThread.stop(); animatorThread = null; } // If the user clicks on the image we stop or restart the animation. public boolean mouseDown(Event e, int x, int y) { if (frozen) { frozen = false; start(); } else { frozen = true; animatorThread = null; } return true; } public void paint(Graphics g) { update(g); } // Draw the image. For all placed pieces and for the piece that is being // dropped, draw the blocks in place. public void update(Graphics g) { int sx, sy, minx, maxx, miny, maxy, o; Rectangle r; g.setColor(Color.black); r = g.getClipRect(); g.fillRect(r.x, r.y, r.width, r.height); minx = r.x >> 4; miny = r.y >> 4; maxx = (r.x + r.width - 1) >> 4; maxy = (r.y + r.height - 1) >> 4; for(int i=0; i<=shape; i++) { sx = x[i]+1; sy = (i == shape) ? pos-1 : y[i]-1; if (sx >= minx-2 && sx <= maxx+1 && sy >= miny && sy <= maxy+3) { o = s[i]*8; for(int j=4; j-- > 0; o += 2) { g.drawImage(block[c[i]], (sx+coords[o])*16, (sy-coords[o+1])*16, this); } } } } public void run() { // Wait until the main block image has loaded. try { tracker.waitForID(0); } catch (InterruptedException e) { return; } // Be nice, lower our priority Thread.currentThread().setPriority(Thread.MIN_PRIORITY); long startTime = System.currentTimeMillis(); // Generate indivicual block images from the montage loaded into blocks. for(int i=0; i<7; i++) { block[i].getGraphics().drawImage(blocks, -i*16, 0, 16*7, 16, this); } // Loop forever while (Thread.currentThread() == animatorThread) { // Move the current piece down one. When it reaches the correct y // position move onto the next piece. When all pieces are placed then // wait. If we've just restarted then repaint the whole image. if (shape == x.length-1 && pos == y[shape]) { shape = -1; } if (shape == -1) repaint(); if (shape < x.length) { if (shape != -1 && pos < y[shape]) { pos++; } else { if (shape < x.length-1) { shape++; pos = 0; } } } // Redraw the changed area of the image. repaint(x[shape]*16, pos*16-96, 48, 96); // Wait delay milliseconds measured from the start of the last frame // before starting the next frame, however, always wait at least 5 // ms. This way animation speed should be independent of processor // load. When the last piece has been placed then wait 5 seconds before // restarting animation. try { startTime += delay; if (shape == x.length-1 && pos == y[shape]) { startTime += 5000; } Thread.sleep(Math.max(5, startTime-System.currentTimeMillis())); } catch (InterruptedException e) { break; } } } }