运动的圆和静止的螺线 · 重制版

这是一篇旧文,其中的内容可能已经过时。

See the Pen Dynamic Circles, Static Spiral by HandsomeOne ( @handsomeone) on CodePen.

原 Processing 代码丑,勿作参考

这是仿照 Bees & Bombs 的风格制作的动画。

/*
Helldweller 同学告诉我, 一个完整的程序应包含 1/3 的代码和 2/3 的注释. 所以
这次我不嫌啰嗦, 尽管代码很短,还是尽量把每一行的意思说得明白, 以免日后看不懂.
*/

// a 控制螺线的形状, l 控制“圆环”的宽度; s 是圆的直径与圆心范数之比, 由 a 和 l 共同决定.
float a, l, s;

void setup() {
  // 画布大小 500*500, 不描边, 帧率 30.
  size(500, 500);
  noStroke();
  frameRate(30);

  a = 1/PI;
  l = -.5;
  // 为保证相邻两圆相切, 圆的直径与圆心范数之比须等于这个数, 在纸上画画就明白了.
  s = 2 * dist(1, 0, pow(2, a*l) * cos(l), pow(2, a*l) * sin(l)) / (1 - pow(2, a*l));
}
void draw(){
  // 局部变量 c 控制了圆盘的颜色.
  int c = 0;
  // x 控制了动画中的每一帧, 从 1 慢->快->慢地变为 -0.99, 再变回 1.
  float x = cos(frameCount%60 * PI/60.0);
  // l*x 意为起始位置与第 0 帧的偏移.
  for (float i = 22 + l*x; i > -15 + l*x; i += l) {
    // 必须先画大圆, 再画小圆, 所以 i 是由大到小.
    // fill(255) -> fill(0) -> fill(255) -> ...
    fill((c += 255) % 510);
    // 画圆. 圆心共处一等角螺线, 直径的选取使得相邻两圆相切.
    ellipse(
      pow(2, a*i) * cos(i) + width/2,
      pow(2, a*i) * sin(i) + height/2,
      s * pow(2, a*i),
      s * pow(2, a*i));
  }

  //  if(frameCount <= 30){
  //    saveFrame("frames/###.gif");
  //  }
  // 将每一帧保存下来以制作动画.
}

制作动画的方法:使用 ImageMagick,在命令行中运行

convert -delay 3 -loop 0 <path/to>/*.gif animation.gif