Mod:Coding Challenge #24: Perlin Noise Flow Field
p5.jsで書かれたものをProcessingに移植するときに、ArrayIndexOutOfBoundsException
が出てしまって解決する方法を考えて、随分書き換えた。グリッドに力場を作って、動くポイントに近い力場の影響を受ける。力場は2次元のパーリンノイズで動きの方向が変わっていく。パーティクルは一定時間でリセットされながら動く。
コード
float inc = 0.01; float scale = 10; int rows, cols; float zoff = 0; Particle[] particles; Field[] flowfield; int num = 500; float gridX, gridY; void setup() { size(960, 540,FX2D); colorMode(HSB, 360, 100, 100, 100); cols = floor(width / scale); rows = floor(height / scale); gridX = width/cols; gridY = height/rows; println(cols, rows); flowfield = new Field[cols * rows]; particles = new Particle[num]; for (int i =0; i < num; i++) { particles[i] = new Particle(); } background(0, 0, 100); } void draw() { fill(0, 0, 100, 10); noStroke(); rect(0, 0, width, height); float yoff = 0; for (int y = 0; y < rows; y++) { float xoff = 0; for (int x = 0; x < cols; x++) { int index = x + y * cols; float theta = noise(xoff, yoff, zoff) * TWO_PI * 4; PVector v = PVector.fromAngle(theta); float px = x * scale; float py = y * scale; v.setMag(1); flowfield[index] = new Field(new PVector(px, py), v); xoff += inc; } yoff += inc; zoff += inc / 300f; } for (int i = 0; i < particles.length; i++) { particles[i].follow(flowfield); particles[i].update(); particles[i].edges(); particles[i].draw(); } } class Field { PVector pos; PVector v; Field(PVector _pos, PVector _v) { pos = _pos; v = _v; } } class Particle { float life; float lifeSpan; PVector pos; PVector vel; PVector acc; float maxSpeed; float brightness; PVector prevPos; Particle() { init(); } void init() { pos = new PVector(random(width), random(height)); vel = new PVector(0, 0); acc = new PVector(0, 0); maxSpeed = 2; brightness = random(100); prevPos = pos.copy(); life = random(1.5, 3); lifeSpan = random(life/300, life/100); } void follow(Field[] flowfield) { for (Field p : flowfield) { if (pos.dist(p.pos) < sqrt(sq(gridX/2)+sq(gridY/2))) { applyForce(p.v); } } } void applyForce(PVector force) { acc.add(force); } void update() { vel.add(acc); vel.limit(maxSpeed); pos.add(vel); acc.mult(0); life -= lifeSpan; if (life < 0) { init(); } } void edges() { if (pos.x > width) { pos.x = 0; updatePrev(); } if (pos.x < 0) { pos.x = width; updatePrev(); } if (pos.y > height) { pos.y = 0; updatePrev(); } if (pos.y < 0) { pos.y = height; updatePrev(); } } void updatePrev() { prevPos = pos.copy(); } void draw() { stroke(0, 0, brightness); brightness = (brightness + 0.1) % 100; line(pos.x, pos.y, prevPos.x, prevPos.y); updatePrev(); } }