/* A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display: >>> A. The instantaneous intersections of the circles B. The aggregate intersections of the circles Implemented by Robert Hodgin <http://flight404.com> 6 April 2004 Processing v.68 <http://processing.org> */ // ******************************************************************************** // INITIALIZE VARIABLES // ******************************************************************************** int xStage = 600; // x dimension of applet int yStage = 600; // y dimension of applet int xMid = xStage/2; // x midpoint of applet int yMid = yStage/2; // y midpoint of applet int totalCircles = 100; // total number of circles Circle[] circle; // Circle object array float gravity; // Strength of gravitational pull float xGrav; // x point of center of gravity float yGrav; // y point of center of gravity float xGravOffset; float angleOffset; float initRadius; float maxDistance; color bgColor; // ******************************************************************************** // SETUP FUNCTION // ******************************************************************************** void setup() { size(600, 600); bgColor = color(255,255,255); background(bgColor); smooth(); colorMode(RGB, 255); ellipseMode(CENTER_RADIUS); noStroke(); framerate(30); createCircles(); } // ******************************************************************************** // MAIN LOOP FUNCTION // ******************************************************************************** void loop(){ if (mousePressed){ createCircles(); } background(bgColor); tellCirclesToBehave(); } void createCircles(){ gravity = .075; maxDistance = 150; angleOffset = random(360); circle = new Circle[totalCircles]; initRadius = 150; for (int i=0; i<totalCircles; i++){ float initAngle = i * 3.6 + angleOffset + random(10); float initTheta = (-((initAngle) * PI))/180; float initxv = cos(initTheta) * initRadius; float inityv = sin(initTheta) * initRadius; float xPos = xMid + initxv; float yPos = yMid + inityv; circle[i] = new Circle(xPos, yPos,0,0, i); } } void tellCirclesToBehave(){ for (int i=0; i<totalCircles; i++){ circle[i].behave(); } } class Circle { int index; // Circle global ID float x; // Circle x position float y; // Circle y position float r; // Circle radius float rBase; // Circle original radius float angle; // Angle of movement in degrees float theta; // Angle of movement in radians float speed; // Speed of movement float xv; // Current velocity along x axis float yv; // Current velocity along y axis boolean[] mightCollide; // Collision might happen boolean[] hasCollided; // Collision is happening float[] distances; // Storage for the distance between circles float[] angles; // Storage for the angle between two connected circles float[] thetas; // Storage for the radians between two connected circles int numCollisions; // Number of collisions in one frame int numConnections; // Total number of collisions float xd; // Distance to target along x axis float yd; // Distance to target along y axis float d; // Distance to target float alphaVar; // Late addition variable for alpha modification float cAngle; // Angle of collision in degrees float cTheta; // Angle of collision in radians float cxv; // Collision velocity along x axis float cyv; // Collision velocity along y axis float gAngle; // Angle to gravity center in degrees float gTheta; // Angle to gravity center in radians float gxv; // Gravity velocity along x axis float gyv; // Gravity velocity along y axis Circle (float xSent, float ySent, float xvSent, float yvSent, int indexSent){ x = xSent; y = ySent; r = 2; index = indexSent; xv = xvSent; yv = yvSent; alphaVar = random(35); mightCollide = new boolean[totalCircles]; hasCollided = new boolean[totalCircles]; distances = new float[totalCircles]; angles = new float[totalCircles]; thetas = new float[totalCircles]; } void behave(){ move(); areWeClose(); areWeColliding(); areWeConnected(); applyGravity(); //move(); render(); reset(); } void areWeClose(){ for(int i=0; i<totalCircles; i++){ if (i != index){ if (abs(x - circle[i].x) < 50 && abs(y - circle[i].y) < 50){ mightCollide[i] = true; } else { mightCollide[i] = false; } } } } void areWeColliding(){ for(int i=0; i<totalCircles; i++){ if (mightCollide[i] && i != index){ distances[i] = findDistance(x, y, circle[i].x, circle[i].y); if (distances[i] < (r + circle[i].r) * 1.1){ hasCollided[i] = true; circle[i].hasCollided[index] = true; angles[i] = findAngle(x,y,circle[i].x,circle[i].y); thetas[i] = (-(angles[i] * PI))/180.0; cxv += cos(thetas[i]) * ((circle[i].r + r)/2.0); cyv += sin(thetas[i]) * ((circle[i].r + r)/2.0); numCollisions += 1; } } } if (numCollisions > 0){ xv = -cxv/numCollisions; yv = -cyv/numCollisions; } cxv = 0.0; cyv = 0.0; } void areWeConnected(){ for(int i=0; i<totalCircles; i++){ if (hasCollided[i] && i != index){ distances[i] = findDistance(x, y, circle[i].x, circle[i].y); if (distances[i] < maxDistance){ angles[i] = findAngle(x,y,circle[i].x,circle[i].y); thetas[i] = (-(angles[i] * PI))/180.0; cxv += cos(thetas[i]) * (circle[i].r/8.0); cyv += sin(thetas[i]) * (circle[i].r/8.0); numConnections += 1; } else { hasCollided[i] = false; circle[i].hasCollided[index] = false; } } } if (numConnections > 0){ xv += (cxv/numConnections)/4.0; yv += (cyv/numConnections)/4.0; } cxv = 0.0; cyv = 0.0; r = numConnections*.85 + 2; } void applyGravity(){ gAngle = findAngle(x,y,xMid,yMid); gTheta = (-(gAngle * PI))/180; gxv = cos(gTheta) * gravity; gyv = sin(gTheta) * gravity; xv += gxv; yv += gyv; } void move(){ x += xv; y += yv; } void render(){ noStroke(); fill(0,25); ellipse(x, y, r, r); fill(0 + r*10,50); ellipse(x, y, r*.5, r*.5); fill(0 + r*10); ellipse(x, y, r*.3, r*.3); if (numCollisions > 0){ noStroke(); fill(0,25); ellipse(x,y, r, r); fill(0,55); ellipse(x,y,r*.85,r*.85); fill(0); ellipse(x,y,r*.7,r*.7); } for(int i=0; i<totalCircles; i++){ if (hasCollided[i] && i < index){ beginShape(LINE_LOOP); xd = x - circle[i].x; yd = y - circle[i].y; stroke(0,150 - distances[i]*2.0); vertex(x,y); vertex(x - xd*.25 + random(-1.0,1.0), y - yd*.25 + random(-1.0,1.0)); vertex(x - xd*.5 + random(-3.0,3.0), y - yd*.5 + random(-3.0,3.0)); vertex(x - xd*.75 + random(-1.0,1.0), y - yd*.75 + random(-1.0,1.0)); vertex(circle[i].x, circle[i].y); endShape(); //line (x, y, circle[i].x, circle[i].y); } } noStroke(); } void reset(){ numCollisions = 0; numConnections = 0; } } float findDistance(float x1, float y1, float x2, float y2){ float xd = x1 - x2; float yd = y1 - y2; float td = sqrt(xd * xd + yd * yd); return td; } float findAngle(float x1, float y1, float x2, float y2){ float xd = x1 - x2; float yd = y1 - y2; float t = atan2(yd,xd); float a = (180 + (-(180 * t) / PI)); return a; }