实现效果见B站 传送门
作品展示见OpenProcessing 传送门
一、基本元素
1. 三种颜色的小圆
其中每个小圆的大小按照正弦函数来变动,产生一种律动感,如下所示。
2. 运行轨道
实际上就一些半透明的线组合拼装,如下所示。前端白色的半圆是由于在每一帧中那一部分没有被重置图层覆盖,具体的在代码实现部分阐述。
3. 粒子
在这一部分,主要是粒子运动和运动模糊。其中粒子的运动轨迹是人为设定的,虽然很麻烦,但是比较实在(主要不知道怎么根据路线来实现粒子按路径运动)。如下图所示。
粒子分为如下几种:
- 红色粒子
- 绿色粒子
- 蓝色粒子
- 彩色粒子
其中彩色粒子的色彩由R,G,B三种颜色随机配比生成。每类粒子的运动轨迹不同,故需要对每一类的粒子的轨迹进行人为设定并编写代码。
二、代码实现
1. 基本代码框架
function setup() {
createCanvas(640,640);
background(204);
}
function draw() {
background(204);
translate(width/2,height/2);
}
2. 三种颜色的小圆实现
首先就是创建圆类,其属性包含
- x、y坐标
- 颜色
其方法只有绘制函数,由于要让三个小圆同频震动,故在绘制函数中加上了参数。定义和调用代码如下所示(非完整连续代码)。
// 定义
class ColorCicle {
constructor(tempx,tempy,tempc) {
this.x = tempx;
this.y = tempy;
this.color = tempc;
}
display(cSize){
push();
noStroke();
fill(this.color);
ellipse(this.x,this.y,cSize,cSize);
pop();
}
}
// 初始化
var gCircle;
var rCircle;
var bCircle;
// 类的实例化
gCircle = new ColorCicle(-width/2+30,0,color(0,255,0,50));
rCircle = new ColorCicle(-width/2+30,-30,color(255,0,0,50));
bCircle = new ColorCicle(-width/2+30,30,color(0,0,255,50));
// 调用绘制函数
var circleSize = map(sin(map(frameCount%60,0,59,0,TWO_PI)),-1,1,10,20);
gCircle.display(circleSize);
rCircle.display(circleSize);
bCircle.display(circleSize);
3. 运行轨道绘制
因为只是几条线的组合拼接,没有什么可以说的,故这里只放上代码(非完整连续代码)。
function drawLine(x1,y1,x2,y2,c,swight) {
push();
stroke(c);
strokeWeight(swight);
line(x1,y1,x2,y2);
pop();
}
// 绘制绿色粒子运动轨迹线
drawLine(-width/2+30,0,-width/2+100,0,color(0,255,0,10),8);
// 绘制红色粒子运动轨迹线
push();
noFill();
strokeJoin(ROUND);
strokeWeight(8);
stroke(255,0,0,10);
beginShape();
vertex(-width/2+30,-30);
vertex(-width/2+100,-30);
vertex(-width/2+100,0);
endShape();
pop();
// 绘制蓝色粒子运动轨迹线
push();
noFill();
strokeJoin(ROUND);
strokeWeight(8);
stroke(0,0,255,10);
beginShape();
vertex(-width/2+30,30);
vertex(-width/2+100,30);
vertex(-width/2+100,0);
endShape();
pop();
// 绘制分叉点的前面一小条线
drawLine(-width/2+100,0,-width/2+130,0,color(255,5),8);
// 绘制混合色粒子运动轨迹线
drawLine(-width/2+130,-300,-width/2+130,300,color(255,5),8);
for(var i = 0;i <= 20;i++){
drawLine(-width/2+130,-300 + i*30,-width/2+180,-300 + i*30,color(255,5),8);
}
4. 粒子
首先定义粒子类(父类),里面包含属性
- x,y坐标
- 粒子半径
- 粒子运动速度
- 粒子是否死亡
包含方法
- 绘制粒子
粒子类代码如下所示
class Particle {
constructor(x,y) {
this.x = x;
this.y = y;
this.r = 5;
this.speed = 0.5;
this.dead = false;
}
display(){
push();
noStroke();
fill(this.color);
ellipse(this.x,this.y,this.r,this.r)
pop();
}
}
然后令红、绿、蓝粒子分别继承Particle类,并添加move()方法来实现粒子运动。三者定义代码如下所示。
class RedParticle extends Particle {
constructor(x,y) {
super(x,y);
this.color = color(255,0,0,50);
}
move() {
if (this.x < -width/2+100) {
this.x += this.speed;
}else if (this.y < 0) {
this.y += this.speed
}
if(this.x >= -width/2+100 && this.y >= 0){
this.dead = true;
}
}
}
class GreenParticle extends Particle {
constructor(x,y) {
super(x,y);
this.color = color(0,255,0,50);
}
move() {
if (this.x < -width/2+100) {
this.x += this.speed;
}
if(this.x >= -width/2+100){
this.dead = true;
}
}
}
class BlueParticle extends Particle{
constructor(x,y){
super(x,y);
this.color = color(0,0,255,50);
}
move(){
if (this.x < -width/2+100) {
this.x += this.speed;
}else if (this.y > 0) {
this.y -= this.speed
}
if(this.x >= -width/2+100 && this.y <= 0){
this.dead = true;
}
}
}
彩色粒子较为复杂,因为其在显示时有两个阶段,一个是在轨道中运动阶段,一个是跑出轨道后的运动阶段。
在轨道中运动阶段,颜色透明度不变,且它可以根据index选择对应的轨道出口;在跑出轨道后的运动阶段,粒子变大,且颜色随着每一帧的进行而逐渐变浅直至透明。代码如下所示。
class MixParticle extends Particle {
constructor(x,y,index) {
super(x,y);
this.color = color(255*random(1),255*random(1),255*random(1));
this.speed = 0.8;
this.index = index;
this.life = random(200,600);
this.bigFlag = false;
}
display(){
push();
noStroke();
if (this.bigFlag) {
this.r = 10;
this.color.setAlpha(map(this.life,0,600,0,230));
}
fill(this.color);
ellipse(this.x,this.y,this.r,this.r)
pop();
}
move() {
if (this.x < -width/2+130) {
this.x += this.speed;
}else{
var moveY = map(this.index,0,20,-300,300);
if (abs(this.y) < abs(moveY)) {
if (moveY > this.y) {
this.y += this.speed;
}else if(moveY < this.y){
this.y -= this.speed;
}
}else {
this.x += this.speed;
if (this.x > -width/2+190) {
this.bigFlag = true;
this.life -= 1;
}
if(this.life <= 0){
this.dead = true;
}
}
}
}
}
通过上述定义,我们便得到了四类的粒子,为了使粒子在死亡时移出相应的粒子数组,我们定义了以下函数,通过此函数,我们便可以实现粒子的运动、显示、循环再生及粒子数组的动态变化。
function particlesMove(particles) {
for(var i = 0;i < particles.length;i++){
if(particles[i].dead){
particles.splice(i,1);
i --;
}else {
particles[i].move();
particles[i].display();
}
}
}
粒子的实例和函数调用如下所示。(非连续代码)
var rParticles = [];
var gParticles = [];
var bParticles = [];
var mParticles = [];
var particleNum = 10;
if (frameCount%30==0) {
var rParticle = new RedParticle(-width/2+30,-30);
rParticles.push(rParticle);
var gParticle = new GreenParticle(-width/2+30,0);
gParticles.push(gParticle);
var bParticle = new BlueParticle(-width/2+30,30);
bParticles.push(bParticle);
if (frameCount >= 155) {
var mParticle = new MixParticle(-width/2+100,0,int(random(21)));
mParticles.push(mParticle);
}
}
particlesMove(rParticles);
particlesMove(gParticles);
particlesMove(bParticles);
particlesMove(mParticles);
为了产生运动模糊效果,我们将画面的一部分进行手动刷新来产生运动模糊效果,而另一部分则不刷新,以产生颜色叠加的效果。为此我们将draw函数中的background(207)进行替换,替换成如下代码。
push();
noStroke();
fill(204,50);
rect(0,0,180,height);
pop();
实现效果见B站 传送门
作品展示见OpenProcessing 传送门
如果对您有帮助的话,欢迎到山月记购买源码支持我(2.2元)!感谢大家的支持!!>_<