Mod:Coding Challenge #56: Attraction and Repulsion Forces
引力と斥力をシミュレーションする.このへんはNature of Codeに書かれてたのでなんとなく手癖で書ける部分がある.アトラクターがパーティクルを引っ張る力を持っていて,そいつに近づきすぎると今度は斥力を発生させて,これまで引っ張っていた力を反転させる.マウスをクリックしたらアトラクターが発生するようにした.あとはそれぞれのパーティクルに寿命を設定して,ライフがゼロになると消えるようにした.
関係ないけど,最近ブログに貼り付けたコードが長くなってきた分,読みづらい気がするので,以下の記事を参考にコードに行数を表示するようにした.読みやすくなったと思う.
追記:3D版も作った.こういうところがPVectorのいいところ.
コード(2D版)
ArrayList<Particle> attractors = new ArrayList<Particle>(); ArrayList<Particle> particles = new ArrayList<Particle>(); float offset =50; void setup() { fullScreen(); colorMode(HSB, 360, 100, 100, 100); for (int i = 0; i < 10; i++) { float x = random(width); float y = random(height); Particle attractor = new Particle(x, y, true); attractors.add(attractor); } background(302, 62, 18); } void draw() { noStroke(); fill(302, 62, 18, 5); rect(0, 0, width, height); for (Particle attractor : attractors) { attractor.update(); attractor.draw(); } for (Particle particle : particles) { for (Particle attractor : attractors) { particle.attracted(attractor); } particle.update(); particle.draw(); } if (random(1) > 0.9) { Particle p = new Particle(random(width), random(height)); particles.add(p); } for (int i = attractors.size()-1; i >= 0; i--) { Particle attractor = attractors.get(i); if (attractor.life < 0) { attractors.remove(i); attractors.add(new Particle(random(width), random(height), true)); } } for (int i = particles.size()-1; i >= 0; i--) { Particle particle = particles.get(i); if (particle.life < 0 && particles.size() > 100) { particles.remove(i); particles.add(new Particle(random(width), random(height))); } } for (Particle particle : particles) { for (Particle attractor : attractors) { particle.attracted(attractor); } particle.update(); particle.draw(); } } void mousePressed() { Particle attractor = new Particle(mouseX, mouseY, true); attractors.add(attractor); } class Particle { PVector pos, prev, vel, acc; boolean isAttractor = false; float life, lifeSpan; Particle(float _x, float _y) { pos = new PVector(_x, _y); prev = new PVector(_x, _y); vel = new PVector(); acc = new PVector(); life = random(1.5, 3); lifeSpan = random(life/300, life/150); } Particle(float _x, float _y, boolean _isAttractor) { pos = new PVector(_x, _y); prev = new PVector(_x, _y); vel = new PVector(); acc = new PVector(); isAttractor = _isAttractor; life = random(1.5, 3); lifeSpan = random(life/300, life/150); } void update() { vel.add(acc); vel.limit(5); pos.add(vel); acc.mult(0); life -= lifeSpan; } void draw() { if (isAttractor) { stroke(337, 98, 51); strokeWeight(16); } else { stroke(191, 93, 81); strokeWeight(4); } line(pos.x, pos.y, prev.x, prev.y); prev.x = pos.x; prev.y = pos.y; } void attracted(Particle target) { PVector force = PVector.sub(target.pos, pos); float mag = force.mag(); mag = constrain(mag, 1, 25); float g = 50; float strength = g / (mag * mag); force.setMag(strength); if (mag < 25) { force.mult(-10); } acc.add(force); } }
コード(3D版)
ArrayList<Particle> attractors = new ArrayList<Particle>(); ArrayList<Particle> particles = new ArrayList<Particle>(); float offset =50; void setup() { fullScreen(P3D); colorMode(HSB, 360, 100, 100, 100); for (int i = 0; i < 10; i++) { float x = random(-width/2, width/2); float y = random(-height/2, height/2); float z = random(-500, 500); Particle attractor = new Particle(x, y, z, true); attractors.add(attractor); } background(302, 62, 18); } void draw() { //noStroke(); //fill(302, 62, 18, 5); //rect(0, 0, width, height); background(302, 62, 18); pushMatrix(); translate(width/2, height/2, -1000); rotateY(frameCount*0.01); rotateZ(PI/7); for (Particle attractor : attractors) { attractor.update(); attractor.draw(); } for (Particle particle : particles) { for (Particle attractor : attractors) { particle.attracted(attractor); } particle.update(); particle.draw(); } if (random(1) > 0.9) { float x = random(-width/2, width/2); float y = random(-height/2, height/2); float z = random(-500, 500); Particle p = new Particle(x, y, z); particles.add(p); } for (int i = attractors.size()-1; i >= 0; i--) { Particle attractor = attractors.get(i); if (attractor.life < 0) { attractors.remove(i); float x = random(-width/2, width/2); float y = random(-height/2, height/2); float z = random(-500, 500); attractors.add(new Particle(x, y, z, true)); } } for (int i = particles.size()-1; i >= 0; i--) { Particle particle = particles.get(i); if (particle.life < 0 && particles.size() > 100) { particles.remove(i); float x = random(-width/2, width/2); float y = random(-height/2, height/2); float z = random(-500, 500); particles.add(new Particle(x, y, z)); } } for (Particle particle : particles) { for (Particle attractor : attractors) { particle.attracted(attractor); } particle.update(); particle.draw(); } popMatrix(); } void mousePressed() { Particle attractor = new Particle(mouseX, mouseY, random(-500, 500), true); attractors.add(attractor); } class Particle { PVector pos, prev, vel, acc; boolean isAttractor = false; float life, lifeSpan; Particle(float _x, float _y, float _z) { pos = new PVector(_x, _y, _z); prev = new PVector(_x, _y, _z); vel = new PVector(); acc = new PVector(); life = random(1.5, 3); lifeSpan = random(life/300, life/150); } Particle(float _x, float _y, float _z, boolean _isAttractor) { pos = new PVector(_x, _y, _z); prev = new PVector(_x, _y, _z); vel = new PVector(); acc = new PVector(); isAttractor = _isAttractor; life = random(1.5, 3); lifeSpan = random(life/300, life/150); } void update() { vel.add(acc); vel.limit(5); pos.add(vel); acc.mult(0); life -= lifeSpan; } void draw() { pushMatrix(); translate(pos.x, pos.y, pos.z); if (isAttractor) { fill(337, 98, 51); noStroke(); box(16); } else { fill(191, 93, 81); noStroke(); box(4); } popMatrix(); prev.x = pos.x; prev.y = pos.y; prev.z = pos.z; } void attracted(Particle target) { PVector force = PVector.sub(target.pos, pos); float mag = force.mag(); mag = constrain(mag, 1, 25); float g = 50; float strength = g / (mag * mag); force.setMag(strength); if (mag < 25) { force.mult(-10); } acc.add(force); } }