[p5.js作品教程]Color Maker 颜色制造机

实现效果见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元)!感谢大家的支持!!>_<

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hzxwonder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值