编程语言:p5.js,p5.js是JavaScript的程式库,它起源于processing的原旨。
p5.js 看起来与 Processing 非常相似,但有一些变化:
参考书籍:中文名《代码本色–用编程模拟自然系统》,英文名是《The Nature of Code》,作者是纽约大学 Tisch 艺术学院艺术教授 Daniel Shiffman。该书用 processing 语言(作者也用其他语言做了相同的事情,可以看作者 github)模拟自然系统,例如模拟加速度、地球引力、粒子系统等等,看起来也蛮有意思。
鼠标点击画面,画面颜色会随之改变。富有流动性。
粒子系统:使用了《代码本色》一书中Ch4中的粒子效果。
交互:鼠标点击,切换线条颜色。
var particles = [];
var nums;
var particleDensity = 4000;
var noiseScale = 800;
var maxLife = 10;
var simulationSpeed = 0.2;
var fadeFrame = 0;
var backgroundColor;
var visualMode = 0;
var numModes = 4;
var invertColors = false;
function setup(){
nums = windowWidth * windowHeight / particleDensity;
backgroundColor = color(20, 20, 20);
createCanvas(windowWidth, windowHeight);
background(backgroundColor);
for(var i = 0; i < nums; i++){
particles[i] = new Particle();
}
}
function draw(){
noStroke();
++fadeFrame;
if(fadeFrame % 5 == 0){
if(invertColors){
blendMode(ADD);
} else {
blendMode(DIFFERENCE);
}
fill(1, 1, 1);
rect(0,0,width,height);
if(invertColors){
blendMode(DARKEST);
} else {
blendMode(LIGHTEST);
}
fill(backgroundColor);
rect(0,0,width,height);
}
blendMode(BLEND);
smooth();
for(var i = 0; i < nums; i++){
var iterations = map(i,0,nums,5,1);
var radius = map(i,0,nums,2,6);
particles[i].move(iterations);
particles[i].checkEdge();
var alpha = 255;
var particleColor;
var fadeRatio;
fadeRatio = min(particles[i].life * 5 / maxLife, 1);
fadeRatio = min((maxLife - particles[i].life) * 5 / maxLife, fadeRatio);
var colorCase = visualMode;
if(visualMode == 0)
{
colorCase = int(particles[i].pos.x / width * 3) + 1;
}
switch(colorCase)
{
case 1:
var lifeRatioGrayscale = min(255, (255 * particles[i].life / maxLife) + red(backgroundColor));
particleColor = color(lifeRatioGrayscale, alpha * fadeRatio);
break;
case 2:
particleColor = particles[i].color;
break;
case 3:
particleColor = color(blue(particles[i].color) + 70, green(particles[i].color) + 20, red(particles[i].color) - 50);
break;
}
if(invertColors){
particleColor = color(255 - red(particleColor), 255 - green(particleColor), 255 - blue(particleColor));
}
fill(red(particleColor), green(particleColor), blue(particleColor), alpha * fadeRatio);
particles[i].display(radius);
}
}
function Particle(){
// member properties and initialization
this.vel = createVector(0, 0);
this.pos = createVector(random(0, width), random(0, height));
this.life = random(0, maxLife);
this.flip = int(random(0,2)) * 2 - 1;
var randColor = int(random(0,3));
switch(randColor)
{
case 0:
this.color = color(110,57,204);
break;
case 1:
this.color = color(7,153,242);
break;
case 2:
this.color = color(255,255,255);
break;
}
// member functions
this.move = function(iterations){
if((this.life -= 0.01666) < 0)
this.respawn();
while(iterations > 0){
var angle = noise(this.pos.x/noiseScale, this.pos.y/noiseScale)*TWO_PI*noiseScale*this.flip;
this.vel.x = cos(angle);
this.vel.y = sin(angle);
this.vel.mult(simulationSpeed);
this.pos.add(this.vel);
--iterations;
}
}
this.checkEdge = function(){
if(this.pos.x > width || this.pos.x < 0 || this.pos.y > height || this.pos.y < 0){
this.respawn();
}
}
this.respawn = function(){
this.pos.x = random(0, width);
this.pos.y = random(0, height);
this.life = maxLife;
}
this.display = function(r){
ellipse(this.pos.x, this.pos.y, r, r);
}
}
function advanceVisual()
{
visualMode = ++visualMode % numModes;
if(visualMode == 0){
invertColors = !invertColors;
backgroundColor = invertColors ? color(235, 235, 235) : color(20, 20, 20);
}
noiseSeed(random()*Number.MAX_SAFE_INTEGER);
background(backgroundColor);
for(var i = 0; i < nums; i++){
particles[i].respawn();
particles[i].life = random(0,maxLife);
}
}
function keyPressed()
{
advanceVisual();
}
function touchStarted()
{
advanceVisual();
}