class Vector2D { float x; float y; Vector2D(float x, float y) { this.x = x; this.y = y; } Vector2D dividedBy(float aFloat) { return new Vector2D(x / aFloat, y / aFloat); } float dot(Vector2D other) { return x * other.x + y * other.y; } float length() { return sqrt(x * x + y * y); } Vector2D minus(Vector2D other) { return new Vector2D(x - other.x, y - other.y); } Vector2D normalized() { return this.dividedBy(this.length()); } Vector2D plus(Vector2D other) { return new Vector2D(x + other.x, y + other.y); } Vector2D reflectionWith(Vector2D normal) { Vector2D reversed = this.times(-1); return normal.times(2).times(reversed.dot(normal)).minus(reversed); } Vector2D times(float aFloat) { return new Vector2D(x * aFloat, y * aFloat); } public String toString() { return "(" + x + ", " + y + ")"; } } class PhysicalState { Vector2D location; Vector2D velocity; PhysicalState(Vector2D location, Vector2D velocity) { this.location = location; this.velocity = velocity; } PhysicalState stateAfterStep(float stepSize) { return new PhysicalState(location.plus(velocity.times(stepSize)), velocity); } } class Collision { Vector2D location; Vector2D normal; Collision(Vector2D location, Vector2D normal) { this.location = location; this.normal = normal; } boolean xMajor() { return abs(normal.x) < abs(normal.y); } } ArrayList colors; ArrayList states; Vector2D up = new Vector2D(0, -1); Vector2D left = new Vector2D(-1, 0); Vector2D down = new Vector2D(0, 1); Vector2D right = new Vector2D(1, 0); int r = 20; void setup() { size(320, 240); smooth(); colors = new ArrayList(); for (int i = 0; i < 30; i++) { color each = color(random(255), random(255), random(255), random(255)); colors.add(new Integer(each)); } states = new ArrayList(); for (int i = 0; i < colors.size(); i++) { Vector2D location = new Vector2D(random(width - r * 2) + r, random(height - r * 2) + r); float velocityR = random(5); float velocityTheta = random(360); Vector2D velocity = new Vector2D(velocityR * cos(radians(velocityTheta)), velocityR * sin(radians(velocityTheta))); states.add(new PhysicalState(location, velocity)); } } void draw() { background(255); for (int i = 0; i < colors.size(); i++) { color eachColor = ((Integer)colors.get(i)).intValue(); PhysicalState eachState = (PhysicalState)states.get(i); stroke(0); strokeWeight(2); fill(eachColor); beginShape(); float first = random(45); for (float theta = first; theta < 360 + first; theta += random(45)) { float x = r * cos(radians(theta)) + eachState.location.x; float y = r * sin(radians(theta)) + eachState.location.y; vertex(x, y); } float x = r * cos(radians(first)) + eachState.location.x; float y = r * sin(radians(first)) + eachState.location.y; vertex(x, y); endShape(); } for (int i = 0; i < states.size(); i++) { PhysicalState each = (PhysicalState)states.get(i); Collision collision = detectCollision(each); if (collision != null) { each.velocity = each.velocity.reflectionWith(collision.normal); } each.location.x += each.velocity.x / 30; each.location.y += each.velocity.y / 30; } } Collision detectCollision(PhysicalState aState) { if (aState.location.y + r >= height && aState.velocity.y > 0) { return new Collision(new Vector2D(aState.location.x, height), up); } else if (aState.location.x + r >= width && aState.velocity.x > 0) { return new Collision(new Vector2D(width, aState.location.y), left); } else if (aState.location.y - r < 0 && aState.velocity.y < 0) { return new Collision(new Vector2D(aState.location.x, 0), down); } else if (aState.location.x - r < 0 && aState.velocity.x < 0) { return new Collision(new Vector2D(0, aState.location.y), right); } else return null; }