当前位置: 首页 > news >正文

Canvas粒子系统终极指南:从基础运动到复杂交互的全流程实现

文章目录

  • 一、粒子系统基础架构
    • 1.1 粒子数据结构设计
    • 1.2 粒子系统管理器
  • 二、基础粒子效果实现
    • 2.1 重力场模拟
    • 2.2 弹性碰撞效果
  • 三、高级交互实现
    • 3.1 鼠标吸引效果
    • 3.2 颜色渐变粒子
  • 四、性能优化策略
    • 4.1 粒子池复用
    • 4.2 分层渲染
  • 五、复杂效果实现
    • 5.1 烟花爆炸效果
    • 5.2 流体模拟


一、粒子系统基础架构

1.1 粒子数据结构设计

class Particle {
  constructor(x, y) {
    this.pos = { x, y };
    this.vel = { x: Math.random()*4 - 2, y: Math.random()*4 - 2 };
    this.acc = { x: 0, y: 0.1 };
    this.size = Math.random()*8 + 2;
    this.life = 200;
  }

  update() {
    this.vel.x += this.acc.x;
    this.vel.y += this.acc.y;
    this.pos.x += this.vel.x;
    this.pos.y += this.vel.y;
    this.life--;
  }
}

1.2 粒子系统管理器

class ParticleSystem {
  constructor() {
    this.particles = [];
    this.emitRate = 5;
    this.gravity = 0.1;
  }

  emit(x, y) {
    for(let i=0; i<this.emitRate; i++) {
      this.particles.push(new Particle(x, y));
    }
  }

  update() {
    this.particles = this.particles.filter(p => p.life > 0);
    this.particles.forEach(p => p.update());
  }
}

二、基础粒子效果实现

2.1 重力场模拟

// 初始化时设置重力
class GravityParticle extends Particle {
  constructor(x, y) {
    super(x, y);
    this.acc.y = 0.3; // 增强重力效果
  }
}

// 鼠标点击触发粒子发射
canvas.addEventListener('click', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  particleSystem.emit(x, y);
});

2.2 弹性碰撞效果

class BounceParticle extends Particle {
  update() {
    super.update();
    
    // 水平边界碰撞
    if(this.pos.x < 0 || this.pos.x > canvas.width) {
      this.vel.x *= -0.8;
      this.pos.x = Math.max(0, Math.min(this.pos.x, canvas.width));
    }
    
    // 垂直边界碰撞
    if(this.pos.y < 0 || this.pos.y > canvas.height) {
      this.vel.y *= -0.8;
      this.pos.y = Math.max(0, Math.min(this.pos.y, canvas.height));
    }
  }
}

三、高级交互实现

3.1 鼠标吸引效果

class AttractorParticle extends Particle {
  constructor(x, y) {
    super(x, y);
    this.attraction = 0.02;
  }

  update(mousePos) {
    super.update();
    
    const dx = mousePos.x - this.pos.x;
    const dy = mousePos.y - this.pos.y;
    const distance = Math.sqrt(dx*dx + dy*dy);
    
    if(distance < 200) {
      const force = (200 - distance) * this.attraction;
      this.vel.x += (dx/distance) * force;
      this.vel.y += (dy/distance) * force;
    }
  }
}

3.2 颜色渐变粒子

class GradientParticle extends Particle {
  constructor(x, y) {
    super(x, y);
    this.colorStart = `hsl(${Math.random()*360}, 80%, 60%)`;
    this.colorEnd = `hsl(${Math.random()*360}, 80%, 30%)`;
  }

  draw(ctx) {
    const gradient = ctx.createRadialGradient(
      this.pos.x, this.pos.y, 
      0, this.pos.x, this.pos.y, this.size
    );
    gradient.addColorStop(0, this.colorStart);
    gradient.addColorStop(1, this.colorEnd);
    
    ctx.beginPath();
    ctx.arc(this.pos.x, this.pos.y, this.size, 0, Math.PI*2);
    ctx.fillStyle = gradient;
    ctx.fill();
  }
}

四、性能优化策略

4.1 粒子池复用

class PooledParticleSystem extends ParticleSystem {
  constructor() {
    super();
    this.pool = [];
  }

  emit(x, y) {
    for(let i=0; i<this.emitRate; i++) {
      const particle = this.pool.length ? this.pool.pop() : new Particle(x, y);
      particle.reset(x, y);
      this.particles.push(particle);
    }
  }

  remove(particle) {
    this.pool.push(particle);
  }
}

4.2 分层渲染

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 背景层(透明粒子)
  backgroundParticles.forEach(p => p.draw(ctx));
  
  // 交互层(高亮粒子)
  interactiveParticles.forEach(p => p.draw(ctx));
  
  requestAnimationFrame(render);
}

五、复杂效果实现

5.1 烟花爆炸效果

class FireworkParticle extends Particle {
  constructor(x, y) {
    super(x, y);
    this.vel.y = -Math.random()*6 - 8;
    this.acc.y = 0.05;
    this.size = Math.random()*15 + 5;
  }

  draw(ctx) {
    ctx.beginPath();
    ctx.arc(this.pos.x, this.pos.y, this.size, 0, Math.PI*2);
    ctx.fillStyle = `hsl(${Math.random()*360}, 80%, 60%)`;
    ctx.fill();
  }
}

5.2 流体模拟

class FluidParticle extends Particle {
  constructor(x, y) {
    super(x, y);
    this.density = Math.random()*50 + 10;
  }

  update() {
    super.update();
    this.vel.x *= 0.95;
    this.vel.y *= 0.95;
  }

  draw(ctx) {
    ctx.beginPath();
    ctx.arc(this.pos.x, this.pos.y, this.size, 0, Math.PI*2);
    ctx.fillStyle = `rgba(0, 255, 255, ${this.density/100})`;
    ctx.fill();
  }
}

到这里,这篇文章就和大家说再见啦!我的主页里还藏着很多 篇 Vue 实战干货,感兴趣的话可以点击头像看看,说不定能找到你需要的解决方案~
创作这篇内容花了很多的功夫。如果它帮你解决了问题,或者带来了启发,欢迎:
点个赞❤️ 让更多人看到优质内容
关注「前端极客探险家」🚀 每周解锁新技巧
收藏文章⭐️ 方便随时查阅
📢 特别提醒:
转载请注明原文链接,商业合作请私信联系
感谢你的阅读!我们下篇文章再见~ 💕

在这里插入图片描述

相关文章:

  • Java 环境变量配置指南
  • 【数学建模】(启发式算法)蚁群算法(Ant Colony Optimization)的详解与应用
  • 深度学习项目--基于SE的ResNet50V2网络结构探究实验
  • 蓝桥杯省模拟赛 互质的数
  • HCIP(VLAN综合实验)
  • 安装Ollama,本地部署deepseek
  • 如何去评估一个系统的高可用
  • 流程引擎/状态机简介以及选型
  • Centos7安装cat美化工具lolcat
  • 使用 flutter_blue_plus 连接蓝牙
  • 3月28号
  • Redis:Hash 类型 内部实现、命令及应用场景
  • 51c嵌入式~MOS~合集1
  • 计算机网络基础:网络流量工程与优化策略
  • Three.js 快速入门教程【二十】3D模型加载优化实战:使用gltf-pipeline与Draco对模型进行压缩,提高加载速度和流畅性
  • Kafka 偏移量
  • python-59-基于python内置库解析html获取标签关键信息
  • python项目整体文件和依赖打包
  • ​Flink/Kafka在python中的用处
  • 局域网共享失败?打印机/文件夹共享工具
  • 袁思达已任中国科学院办公厅主任
  • 上海市重大工程一季度开局良好,崇明线等按既定计划加快建设
  • 市场监管总局等五部门约谈外卖平台企业
  • 习近平出席中拉论坛第四届部长级会议开幕式并发表主旨讲话
  • 6连败后再战萨巴伦卡,郑钦文期待打出更稳定发挥
  • 外企聊营商|波音速度:创新审批促“起飞”