canvas粒子系统需解耦数据、逻辑、渲染三层:particle类封装单个粒子状态与update/draw方法;particlesystem管理批量创建、更新、回收;renderer专注canvas绘制流程;主循环采用固定时间步长分离逻辑更新与渲染。

Canvas粒子系统不是把一堆小圆点画出来就完事,关键在于结构清晰、职责分明、易于扩展。核心是把“数据”“逻辑”“渲染”三者解耦,用面向对象方式组织,避免所有代码堆在requestAnimationFrame里打乱仗。
粒子类(Particle):封装单个粒子的状态与行为
每个粒子应是独立对象,持有自身位置、速度、生命周期、颜色等属性,并提供update()和draw(ctx)方法。不依赖全局变量,也不直接操作Canvas上下文以外的内容。
- 用构造函数或class定义,支持传入初始参数(如随机位置、初速度向量)
-
update()只负责状态演进:位置 += 速度,生命值 -= 衰减量,可加入重力、阻尼、边界反弹等物理逻辑 -
draw(ctx)只做绘制:用ctx.beginPath()→ctx.arc()→ctx.fill(),避免在其中做计算或判断 - 建议加
isDead()方法,便于外部统一回收
粒子系统管理器(ParticleSystem):统一调度与生命周期控制
它不画粒子,也不管单个粒子怎么动,只负责“管人”:批量创建、更新、清理、限制总数、触发发射逻辑。
- 维护一个
particles: Particle[]数组,用Array.filter()或双指针法高效剔除死亡粒子 - 提供
spawn(count, options)方法,支持按需生成(如鼠标点击、定时爆发、跟随路径) - 内置最大数量限制(
maxParticles),防止内存泄漏;新增前先清理陈旧粒子 - 可暴露
reset()、pause()、setEmitter(...)等接口,方便交互控制
渲染器(Renderer):专注Canvas状态与绘制流程
把Canvas上下文操作收拢到一个模块,屏蔽底层细节,让主循环干净利落。
- 封装
clear()(支持全清或半透明拖尾)、resize(canvas)(适配DPR)、setGlobalCompositeOperation()等常用设置 -
render(particles)只遍历并调用每个粒子的draw(ctx),不掺杂更新逻辑 - 支持分层绘制(如背景粒子用
lighter混合,前景用source-over),通过多个Renderer实例实现 - 可集成简单缓动插值,让运动更平滑(如对position做lerp,而非直接赋值)
主循环与时间控制:解耦帧率与逻辑更新
别让requestAnimationFrame直接驱动粒子更新——帧率波动会导致物理行为失真。引入固定时间步长(fixed timestep)机制。
- 记录
lastTime和累计accumulator,每帧根据真实间隔累加,达到1000 / 60 ≈ 16.67ms才执行一次update() - 渲染可高频进行(如60fps),但逻辑更新保持稳定(如30fps),用插值补偿视觉流畅度
- 主循环结构简化为:
update(delta)→render(),二者完全分离 - 避免在
update中做DOM操作、网络请求等阻塞行为
这种分层设计让粒子系统可测试、可复用、可组合。比如换一种渲染目标(WebGL、SVG),只需重写Renderer;想加新粒子类型,继承Particle即可;要做性能分析,各模块可单独打点。不复杂但容易忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










