PoMan3D pm3d; ArrayList snakes = new ArrayList(); void setup() { size(500, 500); pm3d = new PoMan3D(500, 500); strokeWeight(10); Snake first,last; first = new Snake(); last = first; snakes.add(first); for(int i = 0; i < 16; i++){ Snake s = new Snake(); s.target(last); snakes.add(s); last = s; } first.target(last); } float fishscale = 1; void draw() { background(200); if(mousePressed){ if(fishscale < 2.5) fishscale += .03; } else { if(fishscale > 1) fishscale -= .03; } pm3d.setScale(fishscale); pm3d.startDraw(); pm3d.rotateToMouse(); drawTank(); for(Snake s : snakes){ s.move(); s.draw(); } pm3d.endDraw(); } float SPD = .1; class SnakeSpeedPos { float val = random(-100,100),delta = 0; void chase(float t){ if(val > t) { delta -= SPD; } else { delta += SPD; } val += delta; if(val < -100) { val = -100; delta = abs(delta) / 2; } if(val > 100){ val = 100; delta = -abs(delta) / 2; } } void update(){ delta += random(-.5,.5); val += delta; if(val < -100) { val = -100; delta = abs(delta) / 2; } if(val > 100){ val = 100; delta = -abs(delta) / 2; } } } class Snake{ color c = color(random(255),random(255),random(255)); color cs = color(128); SnakeSpeedPos x,y,z; ArrayList segs = new ArrayList(); Snake(){ x = new SnakeSpeedPos(); y = new SnakeSpeedPos(); z = new SnakeSpeedPos(); for(int i = 0; i < 30; i++){ segs.add(new Seg(x.val,y.val,z.val)); } } void move(){ x.chase(targ.x.val); y.chase(targ.y.val); z.chase(targ.z.val); segs.add(0,new Seg(x.val,y.val,z.val)); segs.remove(segs.size()-1); } Snake targ; void target(Snake s){ targ = s; } void draw(){ Seg s = segs.get(0); pm3d.startLinePath(s.x,s.y,s.z,c); for(int i = 1; i < segs.size(); i++){ s = segs.get(i); pm3d.addToLinePath(s.x,s.y,s.z); } pm3d.startLinePath(s.x,100,s.z,cs); for(int i = 1; i < segs.size(); i++){ s = segs.get(i); pm3d.addToLinePath(s.x,100,s.z); } } } class Seg{ float x,y,z; Seg(float px, float py, float pz){ x = px; y = py; z = pz; } } void drawTank() { color BLACK = color(0); //top box pm3d.startLinePath(-100,-100,-100,BLACK); pm3d.addToLinePath(100,-100,-100); pm3d.addToLinePath(100,-100,100); pm3d.addToLinePath(-100,-100, 100); pm3d.addToLinePath(-100,-100, -100); //bottom box pm3d.startLinePath(-100,100,-100,BLACK); pm3d.addToLinePath(100,100,-100); pm3d.addToLinePath(100,100,100); pm3d.addToLinePath(-100,100, 100); pm3d.addToLinePath(-100,100, -100); //up and down pm3d.add3Dline(-100, 100, -100, -100, -100, -100, BLACK); pm3d.add3Dline(-100, 100, 100, -100, -100, 100, BLACK); pm3d.add3Dline(100, 100, -100, 100, -100, -100, BLACK); pm3d.add3Dline(100, 100, 100, 100, -100, 100, BLACK); } class PoMan3D { private float screenCenterX, screenCenterY; private float scaler = 1.0; private float rotateX,rotateY; private ArrayList linesToDraw;// = new ArrayList(); PoMan3D(int w, int h) { screenCenterX = w / 2; screenCenterY = h / 2; } void rotateToMouse(){ rotateX = map(mouseY,screenCenterX,height,0,-2*PI); rotateY = map(mouseX,screenCenterY,width,0,-2*PI); } void setScale(float s){ scaler = s; } void startDraw() { linesToDraw = new ArrayList(); } void addScaledLine(scaledLine s) { for (int i = 0; i < linesToDraw.size(); i++) { scaledLine c = linesToDraw.get(i); if (s.scaleval < c.scaleval) { linesToDraw.add(i, s); return; } } linesToDraw.add(s); } void endDraw() { pushMatrix(); translate(screenCenterX, screenCenterY); for (scaledLine s : linesToDraw) { stroke(s.c); line(s.s1x, s.s1y, s.s2x, s.s2y); } popMatrix(); } private float lastX, lastY, lastZ; private color lastC; void startLinePath(float x, float y, float z, color c) { lastX = x; lastY = y; lastZ = z; lastC = c; } void addToLinePath(float x, float y, float z) { pm3d.add3Dline(lastX, lastY, lastZ, x, y, z, lastC); lastX = x; lastY = y; lastZ = z; } void add3Dline(float x1, float y1, float z1, float x2, float y2, float z2, color c) { float f1x = x1, f2x = x2, f1y = y1, f2y = y2, f1z = z1, f2z = z2; f1x = rotation1(x1, z1, rotateY); f2x = rotation1(x2, z2, rotateY); f1z = rotation2(z1, x1, rotateY); f2z = rotation2(z2, x2, rotateY); f1y = rotation1(y1, f1z, rotateX); f2y = rotation1(y2, f2z, rotateX); f1z = rotation2(f1z, y1, rotateX); f2z = rotation2(f2z, y2, rotateX); float scale1 = map(f1z, -100, 100, .8 * scaler, 1.2 * scaler); float scale2 = map(f2z, -100, 100, .8 * scaler, 1.2 * scaler); f1x *= scale1; f1y *= scale1; f2x *= scale2; f2y *= scale2; addScaledLine(new scaledLine(f1x, f1y, f2x, f2y, scale1+scale2, c)); } private float rotation1(float a, float b, float ang) { return a*cos(ang) - b * sin(ang); } private float rotation2(float a, float b, float ang) { return a*cos(ang) + b * sin(ang); } private class scaledLine { float s1x, s2x, s1y, s2y, scaleval; color c; scaledLine(float ps1x, float ps1y, float ps2x, float ps2y, float pscale, color pc) { c = pc; s1x = ps1x; s1y = ps1y; s2x = ps2x; s2y = ps2y; scaleval = pscale; } void draw() { color(c); line(s1x, s1y, s2x, s2y); } } }