初探 Processing · 重制版

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

See the Pen Stripes by HandsomeOne (@handsomeone) on CodePen.

原 Processing 代码丑,勿作参考

Processing 是一种开源编程语言,专门为电子艺术和视觉交互设计而创建,其目的是通过可视化的方式辅助编程教学,并在此基础之上表达数字创意。Processing 语言建立在 Java 语言的基础之上,但使用简化的语法和图形编程模型。

Processing 官网里提供了丰富的教程样例

我在逛 Windows Store 时,发现了一款“精美、优雅如艺术品的”游戏 Strata - Elegant Puzzler

受它启发,我试图在 Processing 中实现一个,能基于指定的 行数列数宽度边距阴影深度,生成 随机颜色随机“叠放次序” 的彩带的程序。

生成的图像可以作为平铺图案来使用。

实现方法

彩带的条数等于行数加列数,首先生成这么多种随机颜色以备后用。

将每个交点处视作一个单元,每个单元内有两个互相垂直的彩带碎片,连同两边的阴影一起称作 piece。根据位置和方向从先前的颜色列表中决定一种颜色,再随机决定它们的叠放次序。

int M = 21;
int N = 5;
int WIDTH = 23;
int MARGIN = 0;
int SHADOW = 0;

void config(int m, int n, int width, int margin, int shadow){
  M = m;
  N = n;
  WIDTH = width;
  MARGIN = margin;
  SHADOW = shadow;
} // 这个函数留给 processing.js 调用

int SIZE;
int Y_AXIS = -1;
int X_AXIS = 1;
color C1 = color(52, 52, 52, 82);
color C2 = color(52, 52, 52, 1);
color[] C;

class piece {
  int I;
  int J;
  int AXIS;
  piece(int i, int j, int axis) {
    I = i;
    J = j;
    AXIS = axis;
  }
  void display() {
    noStroke();
    // 用数值方法绕过了判断语句,但牺牲了可读性
    // 大意为:
    // 若 AXIS == 1(X_AXIS),则颜色为 C[J+M]
    // 若 AXIS == -1(Y_AXIS),则颜色为 C[I]
    // rect() 部分同理
    fill(C[I * (1 - AXIS) / 2 + (J + M) * (1 + AXIS) / 2]);
    rect((1 - AXIS) / 2 * MARGIN + SIZE * I, (1 + AXIS) / 2 * MARGIN + SIZE * J, (1 + AXIS) * MARGIN + WIDTH, (1 - AXIS) * MARGIN + WIDTH);
    if (AXIS == X_AXIS) {
      setGradient(SIZE * I, MARGIN - SHADOW + SIZE * J, SIZE-1, SHADOW, C2, C1, Y_AXIS);
      setGradient(SIZE * I, WIDTH + MARGIN + SIZE * J, SIZE-1, SHADOW, C1, C2, Y_AXIS);
    } else if (AXIS == Y_AXIS) {
      setGradient(MARGIN - SHADOW + SIZE * I, SIZE * J, SHADOW, SIZE-1, C2, C1, X_AXIS);
      setGradient(WIDTH + MARGIN + SIZE * I, SIZE * J, SHADOW, SIZE-1, C1, C2, X_AXIS);
    }
  }
}

void setup() {
  SIZE = WIDTH + 2 * MARGIN;
  C = new color[M + N];
  for (int i = 0; i < M + N; i++) {
    C[i] = color(random(0, 255), random(0, 255), random(0, 255));
  }
  size(SIZE * M, SIZE * N);
  for (int i = 0; i < M; i++) {
    for (int j = 0; j < N; j++) {
      piece pX = new piece(i, j, X_AXIS);
      piece pY = new piece(i, j, Y_AXIS);
      if (random(-1, 1) < 0) {
        // 运行顺序即叠放次序
        pX.display();
        pY.display();
      } else {
        pY.display();
        pX.display();
      }
    }
  }
  onresize();
}

void draw(){}

void mousePressed () {
  setup();
}

// setGradient() 参考自 http://processing.org/examples/lineargradient.html
void setGradient(int x, int y, float w, float h, color c1, color c2, int axis) {
  noFill();
  strokeCap(SQUARE);
  if (axis == Y_AXIS) {
    for (int i = y; i < y + h; i++) {
      float inter = map(i, y, y + h - 1, 0, 1);
      color c = lerpColor(c1, c2, inter);
      stroke(c);
      line(x, i, x + w, i);
    }
  } else if (axis == X_AXIS) {
    for (int i = x; i < x + w; i++) {
      float inter = map(i, x, x + w - 1, 0, 1);
      color c = lerpColor(c1, c2, inter);
      stroke(c);
      line(i, y, i, y + h);
    }
  }
}

嵌入至网页

Processing.js 是 JQuery 的创始人 John Resig 的又一力作。它能将 Processing 代码转换为 Javascript,再借助 HTML5 中的 canvas 元素展现出来。以下是“生成”按钮调用的函数:

document.getElementById('generate').onclick = function () {
  var m = +document.getElementById('m').value;
  var n = +document.getElementById('n').value;
  var width = +document.getElementById('width').value;
  var margin = +document.getElementById('margin').value;
  var shadow = +document.getElementById('shadow').value;
  var pjs = Processing.getInstanceById('stripe');
  pjs.config(m, n, width, margin, shadow);
  pjs.setup();
};