import Particle; import java.awt.*; import java.applet.*; import java.lang.Math; public class ColorSpots extends DoubleBufferApplet implements Runnable { Particle p1, p2; // levels - these arrays are used to calculate colours float levelp1[][], levelp2[][]; // thread stuff protected Thread animThread; int frameDelay = 250; // grid resolution, window size static final int res = 8; int size; public void init() { this.setBackground(Color.black); this.setForeground(Color.white); update(getGraphics()); String frameDelayString = getParameter("frameDelay"); try { if (frameDelayString != null) frameDelay = Integer.parseInt(frameDelayString); } catch (Exception e) {} size = imageBufferSize.width; // must be square Rectangle box = new Rectangle(0, 0, size, size); p1 = new Particle(box, 30.0, 30.0, 3.0, -2.0, 0.0, 1.0); p2 = new Particle(box, 140.0, 70.0, -5.0, 3.5, 0.0, 1.0); levelp1 = new float[size / res][size / res]; levelp2 = new float[size / res][size / res]; super.init(); redrawImage(); } public void start() { super.start(); animThread = new Thread(this); animThread.start(); } public void stop() { animThread = null; super.stop(); } public void redrawImage() { recalcLevels(p1, levelp1); recalcLevels(p2, levelp2); renderImage(); } // calculate distances to particle from grid points. // level is square of distance - used as an intensity level public void recalcLevels(Particle p, float g[][]) { int x, y; for (x = 0; x < size; x += res) for (y = 0; y < size; y += res) { float d = (float)Math.sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y)); d /= size; if (d > 1) d = 1; g[x/res][y/res] = (1 - d) * (1 - d); } } // draw the level arrays onto the screen public void renderImage() { Graphics g = imageBuffer.getGraphics(); int x, y; clearImageBuffer(); float v1 = (float)(Math.sqrt(p1.vx * p1.vx + p1.vy * p1.vy) / 10); float v2 = (float)(Math.sqrt(p2.vx * p2.vx + p2.vy * p2.vy) / 10); for (x = 0; x < size; x += res) for (y = 0; y < size; y += res) { // green and blue are just the distance to the point. float green = levelp1[x / res][y / res]; float blue = levelp2[x / res][y / res]; // red is proportionate to existing intensity, velocity float red = v1 * green + v2 * blue; if (red > 1.0) red = (float)1.0; red /= 2; // this creates lots of garbage, sadly g.setColor(new Color(red, green, blue)); g.fillRect(x, y, res - 1, res - 1); } if (false) { // draw particles g.setColor(Color.yellow); g.fillRect((int)p1.x - 2, (int)p1.y - 2, 4, 4); g.fillRect((int)p2.x - 2, (int)p2.y - 2, 4, 4); } repaint(); } public void run() { while (Thread.currentThread() == animThread) { Graphics g = imageBuffer.getGraphics(); p1.step(2.0); p2.step(2.0); redrawImage(); applyForces(p1); applyForces(p2); try { Thread.sleep(frameDelay); } catch (InterruptedException ex) { System.out.println("Sleep Interrupted??"); } } } // muck with the particles - friction, can put other things here public void applyForces(Particle p) { double dx, dy; p.vx *= 0.99; // friction p.vy *= 0.99; } // mouse down gives it a little kick.. public boolean mouseDown(Event e, int mouseX, int mouseY) { p1.vx = Math.random() * 10 - 5; p1.vy = -10; p2.vx = Math.random() * 10 - 5; p2.vy = -10; return true; } public void paint(Graphics g) { redrawImage(); } public boolean keyDown(Event e, int key) { if ((char)key == ' ') { if (animThread == null) { animThread = new Thread(this); animThread.start(); } else { animThread = null; } } return true; } }