前两天通读了Cinder 官网上前五章内容,然后用P5 重写了Robert Hodgin 超赞的例子。Tour 中原始的C++ 代码中包含很多的Magic Number,而Hodgin 本人也未在第五章内详细解释其中的一些,所以俺在Processing 代码中也保留了这些Magic Number。
此外,由于俺依然在使用1.5 版的Processing,所以有些地方写得比较累赘,而在新的2.0 beta 版中有很多内部已定义好的函数来取代俺很多累赘的代码。举其中的一个例子:
//Original code and idea by Robert Hodgin (http://roberthodgin.com/)
//Rewritten by Raven Kwok (aka Guo Ruiwen) in Processing
//p1222a_2012_cinderTutorialCh5Rewrite
/*
raystain@gmail.com
flickr.com/ravenkwok
vimeo.com/ravenkwok
weibo.com/ravenkwok
the-moor.blogbus.com
I read through the first five chapters of Cinder tutorial(http://libcinder.org/docs/v0.8.4/hello_cinder_chapter1.html) in the past two days, and rewrote Hodgin's amazing example of particle system in Processing.
*/
ParticleController pc;
boolean mouseDown;
PVector mouseLoc,mousePLoc,mouseVel;
PImage pattern;
void setup(){
size(600,600);
smooth();
frameRate(30);
stroke(255);
ellipseMode(RADIUS);
pattern = loadImage("bunny.jpg");
pc = new ParticleController();
mouseLoc = new PVector(0,0,0);
mousePLoc = new PVector(0,0,0);
mouseVel = new PVector(0,0,0);
}
void draw(){
background(0);
if(mouseDown) pc.addParticles(10,mouseLoc,mouseVel);
pc.repulse();
pc.update(pattern);
pc.display();
}
void mouseDragged(){
mouseMoved();
}
void mousePressed(){
mouseDown = true;
}
void mouseReleased(){
mouseDown = false;
}
void mouseMoved(){
mousePLoc.set(pmouseX,pmouseY,0);
mouseLoc.set(mouseX,mouseY,0);
mouseVel = PVector.sub(mouseLoc,mousePLoc);
}
class Particle{
PVector loc;
PVector vel;
PVector acc;
float mass;
float decay;
float r;
float rDest;
Particle(PVector initLoc, PVector initVel){
loc = initLoc;
vel = initVel;
acc = new PVector(0,0);
decay = random(0.9,0.95);
rDest = 5;
r = 3;
mass = sq(r)*0.0001+0.01;
}
void update(PImage pattern){
vel.add(acc);
float maxVel = r+0.0025;
float velLength = sq(vel.mag())+0.1;
if(velLength>sq(maxVel)){
vel.normalize();
vel.mult(maxVel);
}
loc.add(vel);
vel.mult(decay);
acc.set(0,0,0);
if(loc.x>0 && loc.x<width-1 && loc.y>0 && loc.y<height-1){
int index = floor(loc.x) + floor(loc.y)*pattern.width;
rDest = brightness(pattern.pixels[index])/float(255)*3+0.5;
}else{
rDest = 0.1;
}
r = lerp(r,rDest,0.1);
mass = sq(r)*0.0001+0.01;
}
void display(){
strokeWeight(r*2);
point(loc.x,loc.y);
}
}
class ParticleController{
ArrayList particles;
int initialRandMag = 5;
ParticleController(){
particles = new ArrayList();
}
void addParticles(int amt, PVector mouseLoc, PVector mouseVel){
for(int i=0;i<amt;i++){
float randRadiansLoc = random(2*PI);
PVector initLocOffset = new PVector(cos(randRadiansLoc)*5,sin(randRadiansLoc)*5);
float randRadiansVel = random(2*PI);
float randMagVel = random(1,5);
PVector initVelOffset = new PVector(cos(randRadiansLoc)*randMagVel,sin(randRadiansLoc)*randMagVel);
PVector initLoc = PVector.add(initLocOffset, mouseLoc);
PVector initVel = PVector.add(initVelOffset, mouseVel);
Particle additionalParticle = new Particle(initLoc, initVel);
particles.add(additionalParticle);
}
}
void repulse(){
for(int i=0;i<particles.size();i++){
Particle targetParticle1 = (Particle) particles.get(i);
for(int j=i+1;j<particles.size();j++){
Particle targetParticle2 = (Particle) particles.get(j);
PVector dir = PVector.sub(targetParticle1.loc,targetParticle2.loc);
float thres = (targetParticle1.r+targetParticle2.r)*5;
if( dir.x > -thres && dir.x < thres && dir.y > -thres && dir.y < thres ){
float magnitude = dir.mag();
float distSqrd = pow(magnitude,3);
if(distSqrd>0){
float pushingForce = 1/distSqrd;
dir.normalize();
dir.mult(pushingForce);
PVector accOffset1 = PVector.div(dir,targetParticle1.mass);
PVector accOffset2 = PVector.div(dir,targetParticle2.mass);
targetParticle1.acc.add(accOffset1);
targetParticle2.acc.sub(accOffset2);
}
}
}
}
}
void update(PImage pattern){
for(int i=0;i<particles.size();i++){
Particle targetParticle = (Particle) particles.get(i);
targetParticle.update(pattern);
}
}
void display(){
for(int i=0;i<particles.size();i++){
Particle targetParticle = (Particle) particles.get(i);
targetParticle.display();
}
}
}