// A block of particles in the centre of an area // each particle detaches and moves away int canvasWidth; int canvasHeight; int numX = 200; int numY = 150; int numParticles; particle[] particles = new particle[numX * numY]; particle[] unmoved = new particle[numX * numY]; void setup(){ canvasWidth = 600; canvasHeight = 600; background(255); size(canvasWidth,canvasHeight); stroke(0); int c=0; int startX = (int)-Math.floor(numX/2); int startY = (int)-Math.floor(numY/2); for(int b=0; b < numY; b++){ for(int a=0; a < numX; a++){ particles[c] = new particle( startX + a, startY + b, c ); // Allocate neighbours if(b>0) { particles[c].setParticleDown(c - numX); } if(b0) { particles[c].setParticleLeft(c-1); } if(a 0.99) { particles[i].activate(); } particles[i].change(); } } int sX(int cX) { return cX + (canvasWidth/2); } int sY(int cY) { return canvasHeight/2 - cY; } class particle{ boolean active; int xPos; int yPos; float speed; float direction; boolean potentiallyActive = false; int left, right, up, down;; boolean hasLeft, hasRight, hasDown, hasUp = false; int index; particle( int x, int y, int c){ xPos = x; yPos = y; active = false; direction = (float)Math.random() * 2 * PI; speed = ((float)Math.random() * 2) + 3; index = c; } void move(){ float dx = cos(direction) * speed; float dy = sin(direction) * speed; xPos = (int)(xPos + dx); yPos = (int)(yPos + dy); } void draw(){ if(potentiallyActive){ stroke(255,0,0); }else{ stroke(0); } point( sX(xPos), sY(yPos) ); } void change(){ if(active && (xPos < canvasWidth || xPos > -canvasWidth) && (yPos > - canvasHeight || yPos < canvasHeight)){ move(); } this.draw(); } void noneighbours() { if(! active){ if(hasRight && particles[right].active && hasLeft && particles[left].active && hasDown && particles[down].active && hasUp && particles[up].active) { active = true; direction = (float)(Math.random() * 2 * Math.PI); } } } void activate(){ // First, see if we can activate // We need one gap, and one gap only // if there is a gap, we have to head in that direction // If there is more than one gap, then that opens the choice of direction if(! active) { boolean canleft = false; boolean canright = false; boolean canup = false; boolean candown = false; float possDir = (float)( Math.random() * Math.PI/2 ); if(! hasUp || (hasUp && particles[up].active == true)){ active = true; direction = possDir + (float)Math.PI/4; } if(!hasLeft || (hasLeft && particles[left].active == true)){ direction = possDir + (float)Math.PI * 3/4; active = true; } if(! hasRight || (hasRight && particles[right].active == true)){ direction = possDir + (float)Math.PI * 7/4; active = true; } if(! hasDown || (hasDown && particles[down].active == true)){ direction = possDir + (float)Math.PI * 5/4; active = true; } } } void setParticleUp(int up){ this.hasUp = true; this.up = up; } void setParticleDown(int down){ this.hasDown = true; this.down = down; } void setParticleLeft(int left){ this.hasLeft = true; this.left = left; } void setParticleRight(int right){ this.hasRight = true; this.right = right; } }