canvas动态粒子轨迹的关键在于维护历史坐标数组而非仅更新当前位置,每个粒子需存储trail数组并控制长度,绘制时用lineto连线配合渐变描边实现流动感,轨迹不参与物理计算且可结合时间戳支持回放暂停。

粒子轨迹需要单独维护历史坐标数组
每个粒子不能只保存当前 x、y,还得配一个轨迹数组(比如 trail = [])。每次更新位置后,把新坐标 push 进去;同时控制长度,避免无限增长(例如最多保留 30 个点):
- 用
trail.push({x, y})记录当前位置 - 用
trail.length > maxLen && trail.shift()控制轨迹长度 - 绘制时遍历
trail,用lineTo或bezierCurveTo连线,比逐点画圆更显“流动感”
轨迹绘制推荐用路径+渐变描边
直接用 stroke() 画一条带透明度/粗细变化的线,比画一堆半透明圆点更高效、更顺滑:
- 调用
ctx.beginPath()后,用moveTo(trail[0].x, trail[0].y)起笔 - 循环
lineTo(p.x, p.y)连接后续点 - 设置
ctx.strokeStyle = 'rgba(100, 200, 255, 0.6)',并用ctx.lineWidth = 1.2或随索引动态缩放 - 进阶可配合
createLinearGradient实现起点粗亮、终点细淡的视觉动效
性能优化:轨迹不参与碰撞检测与物理计算
轨迹只是视觉残留,不该参与逻辑运算。常见误区是把轨迹点也当作“粒子”去判断距离、连线或施加力——这会大幅拖慢帧率:
- 粒子本体(位置、速度、半径)负责所有物理更新和交互逻辑
- 轨迹数组仅在
render阶段读取,不参与update循环 - 若需长轨迹但内存受限,可用定点步进法:每 N 帧记录一次坐标,而非逐帧
支持回放与暂停的关键是分离时间轴
真正可回放的轨迹,依赖独立的时间戳或帧序号记录,而不是靠 requestAnimationFrame 的实时节奏:
- 存储时加字段:
{x, y, time: performance.now()} - 播放时根据当前时间差值,插值计算中间位置(如线性插值
lerp(a, b, t)) - 暂停只需冻结更新逻辑,轨迹数组照常绘制——画面停住,线条仍在











