创意编程Canvas

用 Canvas 画一个会呼吸的粒子世界

从一个点到一片星网,理解动画循环、距离检测与交互反馈的基本原理。

示例文章:介绍本站粒子实验使用的基本原理,不是个人经历或性能研究报告。

从一个粒子开始

粒子不是某种复杂对象。最小实现只需要位置、速度与半径。每一帧更新位置,再把圆点画到画布上,就能让它动起来。

interface Particle {
  x: number;
  y: number;
  vx: number;
  vy: number;
}

function advance(particle: Particle, delta: number) {
  particle.x += particle.vx * delta;
  particle.y += particle.vy * delta;
}

这里的 delta 是经过限制的时间步长,用于降低不同屏幕刷新率造成的速度差异。切回后台标签页时,也要防止一次累积过大的时间间隔。

两个点,什么时候连线

计算两个点的平方距离,与连线半径的平方比较即可。只有足够近的粒子才画线,距离越远,线条透明度越低。

const dx = a.x - b.x;
const dy = a.y - b.y;
const distanceSquared = dx * dx + dy * dy;
const connected = distanceSquared < connectionRadius ** 2;

最直接的算法会比较每一对粒子,复杂度是 O(n²)。对于数量受限的小实验,它足够清楚;如果需要成千上万的粒子,再考虑空间网格或其他邻域查询结构。

把指针变成引力源

指针附近的粒子可以产生轻微偏移,为画面提供可感知的反馈。移动端则应保留正常的页面滚动,而不是让整个画布截获所有手势。

交互反馈应当克制:过强的吸引力会让粒子迅速聚成一团,过强的排斥力则会把画面清空。

动画之外的体验

一个完整实验还需要暂停按钮、可理解的参数名称,以及减少动画偏好的支持。用户选择减少动画时,默认显示静态帧,并让他们主动决定是否开始播放。

当画布离开视口或页面进入后台时暂停绘制,可以节省不必要的计算。设备像素比也应设置上限,避免高分屏上的绘制成本过高。

亲手试一试

打开交互式粒子场,改变粒子数量和连线距离。观察哪一种参数组合让结构清晰,哪一种会让画面变得拥挤。视觉参数没有唯一正确答案,实际试验比猜测更有帮助。