// string_0 (2005. 2. 14.) // by SeungJoon Choi // erucipe@hanmail.net // // http://processing.org Bone[] all_bones; Fish[] fishes; int n_all_bones; int n_fishes; int n_bones; void setup() { size(400, 300); background(0); ellipseMode(CENTER_RADIUS); rectMode(CENTER_RADIUS); n_bones = 100; n_fishes = 1+(int)random(2.5); n_all_bones = n_fishes * n_bones; all_bones = new Bone[n_all_bones]; for(int i = 0; i < n_all_bones; i++) { all_bones[i] = new Bone(); all_bones[i].Setup(i, random(width), random(height), 4, random(TWO_PI)); } fishes = new Fish[n_fishes]; for(int i = 0; i < n_fishes; i++) { fishes[i] = new Fish(); fishes[i].Setup(i*n_bones); } } void loop() { //background(255); stroke(255, 255, 255, 16); for(int i = 0; i < n_fishes; i++) { Fish fish = fishes[i]; fish.Update(); fish.Draw(); } for(int i = 0; i < n_all_bones; i++) { Bone bone = all_bones[i]; bone.Update(); //bone.Draw(); } blur(g); } class Bone { Bone() { x = 0; y = 0; vx = 0; vy = 0; radius = 5; dir = 0; dt = 0.2; } void Setup(int _id, float _x, float _y, float _radius, float _dir) { id = _id; x = _x; y = _y; radius = _radius; dir = _dir; } void Update() { dynamics(); antiField(); } void dynamics() { x += vx*dt; y += vy*dt; } void antiField() { for(int i = 0; i < n_all_bones; i++) { Bone bone = all_bones[i]; if(this != bone) { float dx = x - bone.x; float dy = y - bone.y; float d = sqrt(dx*dx + dy*dy); if(d > 0) { float R = radius + bone.radius; if(d < R) { float k = R - d; float ux = dx / d; float uy = dy / d; /* x += k*ux*0.5; y += k*uy*0.5; bone.x += -k*ux*0.5; bone.y += -k*uy*0.5; */ x += k*ux; y += k*uy; //dir = atan2(uy, ux); //dir = atan2(dy, dx); } } } } } void Draw() { push(); translate(x, y, 0); rotateZ(dir + PI*0.5); //ellipse(0, 0, radius, radius); rect(0, 0, radius, radius); pop(); } int id; float x, y, vx, vy, dir, radius, dt; } class Fish { Fish() { x = 0; y = 0; vx = 0; vy = 0; dir = 0; view_radius = 100; dt = 0.2; bones = new Bone[n_bones]; temp = new Bone(); } void Setup(int n) { int j = 0; for(int i = n; i < n + n_bones; i++) { bones[j] = all_bones[i]; if(j > 0) { float R = bones[j-1].radius + bones[j].radius; bones[j].x = bones[j-1].x + R*cos(bones[j-1].dir); bones[j].y = bones[j-1].y + R*sin(bones[j-1].dir); bones[j].dir = bones[j-1].dir; } else { x = bones[j].x; y = bones[j].y; dir = bones[j].dir; } j++; } } void Update() { float dx = mouseX - x; float dy = mouseY - y; float d = sqrt(dx*dx+dy*dy); if(d > 0) { vx += dx/d; vy += dy/d; } x += vx*dt; y += vy*dt; vx *= 0.99; vy *= 0.99; maintainForm(); } void maintainForm() { float dx, dy, d, R, ux, uy; for(int i = 0; i < n_bones; i++) { Bone bone = bones[i]; Bone parent = temp; if(i > 0) { parent = bones[i-1]; } else { dx = x - bones[0].x; dy = y - bones[0].y; d = sqrt(dx*dx + dy*dy); temp.x += dx*dt; temp.y += dy*dt; } dx = parent.x - bone.x; dy = parent.y - bone.y; d = sqrt(dx*dx + dy*dy); R = parent.radius + bone.radius; if(d > R) { float k = R - d; ux = dx / d; uy = dy / d; bone.x += -k*ux; bone.y += -k*uy; bone.dir = atan2(dy, dx); bone.vx += ux; bone.vy += uy; bone.dir = atan2(dy, dx); bone.vx *= 0.9; bone.vy *= 0.9; } else { bone.vx *= 0.8; bone.vy *= 0.8; } } } void Draw() { push(); translate(x, y, 0); rotateZ(dir + PI*0.5); //ellipse(0, 0, 10, 10); //rect(0, 0, radius, radius); pop(); //beginShape(TRIANGLE_STRIP); beginShape(LINE_STRIP); float r = 4; for(int i = 0; i < n_bones; i++) { //r = 20 + 20*sin((float)i / (float)n_bones * TWO_PI); Bone bone = bones[i]; //vertex(bone.x + r*cos(bone.dir + PI*0.5), bone.y+r*sin(bone.dir + PI*0.5)); //vertex(bone.x + r*cos(bone.dir - PI*0.5), bone.y+r*sin(bone.dir - PI*0.5)); curveVertex(bone.x, bone.y); } endShape(); } Bone temp; Bone[] bones; int id; float x, y, vx, vy, dir, view_radius, dt; } int Red(int c) { return (c & 0xff0000) >> 16; } int Green(int c) { return (c & 0x00ff00) >> 8; } int Blue(int c) { return c & 0x0000ff; } void blur(BGraphics target) { float divider = 5 + (1-random(2))*0.1; int index,left,right,top,bottom; int sumr, sumg, sumb; for(int j=0;j0) left=-1; else left=width-1; if(j==(width-1)) right=-width+1; else right=1; if(i>0) top=-width; else top=(height-1)*width; if(i==(height-1)) bottom=-(height-1)*width; else bottom=width; // Calculate the sum of n neighbors sumr=Red(target.pixels[left+index]); // left middle sumg=Green(target.pixels[left+index]); sumb=Blue(target.pixels[left+index]); sumr+=Red(target.pixels[right+index]); // right middle sumg+=Green(target.pixels[right+index]); sumb+=Blue(target.pixels[right+index]); sumr+=Red(target.pixels[index]); // middle middle sumg+=Green(target.pixels[index]); sumb+=Blue(target.pixels[index]); sumr+=Red(target.pixels[index+top]); // middle top sumg+=Green(target.pixels[index+top]); sumb+=Blue(target.pixels[index+top]); sumr+=Red(target.pixels[index+bottom]); // middle bottom sumg+=Green(target.pixels[index+bottom]); sumb+=Blue(target.pixels[index+bottom]); sumr=(int)((float)sumr/divider); sumg=(int)((float)sumg/divider); sumb=(int)((float)sumb/divider); target.pixels[index]=(sumr<<16)+(sumg<<8)+sumb; } } }