/** * Chaser class * http://subpixels.com * 2009-12-27 */ public class Chaser { PVector pos; // Current chaser position float speed = 15; // Default speed float size = 20; // Default size color headColor = 0xCCCC00; // Colour or chaser float spinSpeed = 0.01; // Rotation speed float spinOffset = 0; // Current rotation angle int maxTailLength = 10; // Number of points in tail ArrayList tail; // Trail of locations public Chaser() { randomise(); } public void randomise() { randomPosition(0, 0, -500, width, height, 0); randomSpeed(); randomSize(); randomColor(); randomSpin(); } public void randomPosition(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { pos = new PVector(random(minX, maxX), random(minY, maxY)); if (useZ) pos.z = random(minZ, maxZ); // Clear tail to avoid strange disjoint tail = new ArrayList(maxTailLength); } public void randomSpeed() { speed = random(100) + 1; } public void randomSize() { size = random(50) + 5; } public void randomColor() { headColor = int(random(0x1000000)) | 0x33000000; } public void randomSpin() { spinSpeed = random(-0.1, 0.1); spinOffset = random(TWO_PI); } // Chase the target public void update(PVector target, float targetSize) { // Spin! spinOffset += spinSpeed; // Don't do anything else if paused if (paused || millis() < waitUntil) return; // Add to the tail if (tail.size() >= maxTailLength) tail.remove(0); tail.add(pos.get()); // Get direction (difference between target and // current chaser position) PVector chaserToTarget = PVector.sub(target, pos); // Don't chase if already close enough float distanceToTarget = chaserToTarget.mag(); if (distanceToTarget < size) return; // We could use normalize() then mult(chaserSpeed), but // if the chaser is close to the target then it will keep // jumping past the target instead of just arricving at it! // limit() will instead limit to magnitude to at most the // speed we want in the direction to the target. chaserToTarget.limit(distanceToTarget - size - targetSize); chaserToTarget.limit(speed); // Move towards the target pos.add(chaserToTarget); } public void display() { pushMatrix(); pushStyle(); strokeWeight(3); if (tail.size() > 0) { PVector p; stroke(red(headColor), green(headColor), blue(headColor), alpha(headColor)); fill(red(headColor), green(headColor), blue(headColor), alpha(headColor) / 4); beginShape(); curveVertex(pos.x, pos.y, pos.z); for(int i = tail.size() - 1; i >= 0; i--) { p = (PVector)tail.get(i); curveVertex(p.x, p.y, p.z); } endShape(); } stroke(255, 100); // Z-axis pole to show position if (useZ) { line(pos.x, pos.y, 0, pos.x, pos.y, -500); } translate(pos.x, pos.y, pos.z); rotateZ(spinOffset); // Mark centre line(-size, 0, 0, size, 0, 0); line(0, -size, 0, 0, size, 0); noStroke(); fill(red(headColor), green(headColor), blue(headColor), alpha(headColor)); sphere(size); stroke(255); noFill(); // Surround sphere with circles aligned with chaser's axes float diam = size * 2 + 2; ellipse(0, 0, diam, diam); rotateX(HALF_PI); ellipse(0, 0, diam, diam); rotateY(HALF_PI); ellipse(0, 0, diam, diam); popStyle(); popMatrix(); } }