// us is them - mitchell whitelaw - october 2006 // raw visualisation int numBits = 200; // float gravity = -0.005; float friction = 0.95; float inertia = 0.1; float velFactor = 0.07; // int drawing = 0; int totalDrawing = 0; int originX; int originY; int cloudX; int cloudY; Particle[] theCloud; // the array of particles void setup() { size (800,600); framerate(30); ellipseMode(CENTER_RADIUS); smooth(); makeCloud(); } void makeCloud() { theCloud = new Particle[numBits]; for (int i=0; i < numBits; i++){ float xPos = random(width); float yPos = random(height); int theShade = int(random(255)); theCloud[i] = new Particle(xPos,yPos,0,0,i,0,0,0,0,theShade); // x,y,xvel,yvel,particle ID } } class Particle { int id; // particle ID float x; // x position float y; // y position float xvel; // x velocity float yvel; // y velocity int myNeighbour; // ID of my neighbour int myNeighbour2; float neighbourDistance; // distance to my neighbour float neighbourDistance2; int drawingFlag; // am I drawing or not? float Shade; // my shade Particle(float xIn, float yIn, float xvelIn, float yvelIn, int idIn, int myNeighbourIn, float neighbourDistanceIn, int myNeighbourIn2, int neighbourDistanceIn2, float myShade) { // particle constructor x = xIn; y = yIn; xvel = xvelIn; yvel = yvelIn; id = idIn; myNeighbour = myNeighbourIn; myNeighbour2 = myNeighbourIn2; neighbourDistance = neighbourDistanceIn; neighbourDistance2 = neighbourDistanceIn2; drawingFlag = 1; Shade = myShade; } void moveParticle(){ if (abs(xvel)+abs(yvel) > inertia){ x=(x+xvel); y=(y+yvel); } xvel = xvel*friction; yvel = yvel*friction; } void findNeighbour(){ int theNeighbour = 0; int thenextNeighbour = 0; float minDistance = 10000; // make it a high number so we can find the minimum float nextminDistance = 10000; float theDistance = 0; for (int i=0; i < numBits; i++){ theDistance = sqrt(sq(x - theCloud[i].x) + sq(y - theCloud[i].y)); // distance from this particle to each of the others if (theDistance < minDistance && theDistance > 1){ // if the distance is less than the lowest yet, and more than 0 (ie it's not the distance from me to me). minDistance = theDistance; theNeighbour = i; } if (theDistance < nextminDistance && theDistance > minDistance){ nextminDistance = theDistance; thenextNeighbour = i; } } myNeighbour = theNeighbour; // the ID of the neighbour particle neighbourDistance = minDistance; myNeighbour2 = thenextNeighbour; neighbourDistance2 = nextminDistance; } void neighbourAttract(int whichParticle){ float xOffset = x - theCloud[whichParticle].x; float yOffset = y - theCloud[whichParticle].y; float thisDistance = sqrt(sq(xOffset) + sq(yOffset)); float absOffset = abs(xOffset) + abs(yOffset); float xRatio = xOffset/absOffset; // ratio of x/y - using abs to maintain sign of offset float yRatio = yOffset/absOffset; // ratio of y/x xvel += velFactor*xRatio*((abs(Shade-theCloud[whichParticle].Shade))/255); // the initial X velocity yvel += velFactor*yRatio*((abs(Shade-theCloud[whichParticle].Shade))/255); // the initial Y velocity } void globalGravity(){ float xOffset = x - (width/2); float yOffset = y - (height/2); float absOffset = abs(xOffset) + abs(yOffset); float xRatio = xOffset/absOffset; // ratio of x/y - using abs to maintain sign of offset float yRatio = yOffset/absOffset; // ratio of y/x xvel += gravity*xRatio; yvel += gravity*yRatio; } void shadeParticle() { float averageShade = 0.5*(theCloud[myNeighbour].Shade + theCloud[myNeighbour2].Shade); float neighbourDifference = abs(theCloud[myNeighbour].Shade - theCloud[myNeighbour2].Shade); float theDifference = Shade-averageShade; if (abs(theDifference) > 20 && abs(theDifference) < 40){ // a bit different, but not too much -- get closer to the average if (theDifference <= 0) { Shade = min(255,Shade+1); } else { Shade = max(0,Shade-1); } } if (neighbourDifference < 10 && (abs(theDifference)<15 || abs(theDifference) > 240)){ // the same, or very different - get more different if (theDifference <= 0) { Shade = max(0,Shade-1); } else { Shade = min(255,Shade+1); } } } void drawParticle() { noStroke(); fill(Shade); ellipse(x,y,10,10); } } void draw(){ background(120,120,255); for (int i=0; i < numBits; i++){ theCloud[i].findNeighbour(); // find neighbour once only - when cloud is made theCloud[i].neighbourAttract(theCloud[i].myNeighbour); theCloud[i].neighbourAttract(theCloud[i].myNeighbour2); theCloud[i].drawParticle(); theCloud[i].shadeParticle(); theCloud[i].moveParticle(); theCloud[i].globalGravity(); } }