基于canvas编写的音频可视化粒子特效

1.此模块是未完成品,希望广大程序员能够帮我指出该怎么改写一下以满足我的需求,我想要做的是音频可视化的粒子特效模块可以绑定到指定的区域中,但是现在受限于自身的数学水平,实在是没招了,以下贡献出我的所有代码,希望有大佬可以指出该怎么改写可以满足我的要求。

现在主要BUG:每个粒子生成后他的移动角度是全随机,我希望可以做成围绕大圆发散的移动角度,也就是说如果把这个大圆的中点作为直角坐标系的原点我希望在第一象限的粒子只会往第一象限移动,其他以此类推。。

2.代码


class cirlular{
	constructor(mycanvas, _this) {
	    const ctx = uni.createCanvasContext(mycanvas);
	    this.ctx = ctx;
	    let height = 0;
	    let width = 0;
		this.radius = 100; // 大圆的半径
	    // 圆粒子所在位置以及移动方位
	    this.circleArray = [];
	    const query = uni.createSelectorQuery().in(_this);
	    query.select('#particleCanvas').fields({ node: true, size: true }).exec((res) => {
	      height = res[0].height;
	      width = res[0].width;
	    })
	    this.height = height;
	    this.width = width;
	    this.numParticles = 3000; // 初始小粒子的数量
	    this.initParticles();
	    this.initdraw();
	  }
	
	  /**
	   * 渲染画面
	   * @param {}
	   * @return {*}
	   */
	  initdraw() {
	    this.ctx.draw(true);
	  }
	
	  // 初始化粒子
	  initParticles() {
	    const centerX = this.width / 2;
	    const centerY = this.height / 2;
	    
	    const angleIncrement = (2 * Math.PI) / this.numParticles; // 每个小粒子之间的角度增量
	
	    this.ctx.arc(centerX, centerY, this.radius, 0, 2 * Math.PI);
	    this.ctx.setFillStyle('#ffffff');
	    this.ctx.fill();
	
	    for (let i = 0; i < this.numParticles; i++) {
	      const angle = i * angleIncrement; // 计算当前小粒子的角度
	      const x = centerX + this.radius * Math.cos(angle); // 计算小粒子的X坐标
	      const y = centerY + this.radius * Math.sin(angle); // 计算小粒子的Y坐标
	
	      // 初始化小粒子,包括位置、速度、透明度、生命周期等信息
	      const particle = {
	        x: x,
	        y: y,
	        dx: Math.random() * 2 - 1, // 随机X轴的速度
	        dy: Math.random() * 2 - 1, // 随机Y轴的速度
	        opacity: 1, // 初始透明度
	        lifespan: Math.floor(Math.random() * 100), // 随机生命周期
	      };
	      this.circleArray.push(particle);
	    }
	  }
	
	  // 更新和渲染粒子
	  updateAndRenderParticles() {
	    for (let i = this.circleArray.length - 1; i >= 0; i--) {
	      const particle = this.circleArray[i];
	      particle.x += particle.dx;
	      particle.y += -particle.dy;
	      particle.opacity -= 0.01; // 透明度逐渐减小
	      particle.lifespan--;
	
	      if (particle.opacity <= 0 || particle.lifespan <= 0) {
	        // 如果透明度为0或生命周期结束,从数组中移除粒子
	        this.circleArray.splice(i, 1);
	        // 添加新的粒子在起始位置,继续运动
	        this.addNewParticle();
	      } else {
	        // 绘制小粒子
	        this.ctx.beginPath();
	        this.ctx.arc(particle.x, particle.y, 0.3, 0, 2 * Math.PI);
	        this.ctx.setFillStyle(`rgba(255, 0, 0, ${particle.opacity})`);
	        this.ctx.fill();
	      }
	    }
	  }
	
	  // 添加新的粒子在起始位置,继续运动
	  addNewParticle() {
	    const centerX = this.width / 2;
	    const centerY = this.height / 2;
	    // const radius = 60; // 大圆的半径
	
	    const angle = Math.random() * (2 * Math.PI); // 随机角度
	    const x = centerX + this.radius * Math.cos(angle); // 计算小粒子的X坐标
	    const y = centerY + this.radius * Math.sin(angle); // 计算小粒子的Y坐标
	// 1 , -1 右下 1 ,1 右上 -1 ,-1 左下 -1 ,1 左上
	    const newParticle = {
	      x: x,
	      y: y,
	      dx: Math.random() * 2 - 1 , // 随机X轴的速度 ,可能是要这里修改一下
		  // dx: -1,
	      dy: Math.random() * 2 - 1 , // 随机Y轴的速度,还有这里,但是实在不懂怎么改
		  // dy: 1,
	      opacity: 1, // 初始透明度
	      lifespan: Math.floor(Math.random() * 100), // 随机生命周期
	    };
	    this.circleArray.push(newParticle);
	  }
	
	  // 主循环
	  startAnimation() {
	      this.animationInterval = setInterval(() => {
	        this.ctx.clearRect(0, 0, this.width, this.height);
	        this.updateAndRenderParticles();
	        this.ctx.draw();
	      }, 20); // 16毫秒对应约60帧每秒
		}
	}
module.exports = cirlular;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值