前端小玩意 Processing 学习笔记 ← 返回作品集

笔记 · 创意编程

把 Processing 和 p5.js 放在一起学

这是一份我自己整理的学习笔记:Processing 是什么、它和网页里的 p5.js 到底什么关系、 环境怎么搭、常用函数怎么一一对应。最后附一个完整的"撞墙反弹小球", Processing 和 p5.js 两个版本并排放,方便对照着抄。

一、Processing 是什么

一句话:Processing 是给「画画」和「做交互」准备的一门编程语言,外加一个自带运行按钮的 IDE。 它由 Casey Reas 和 Ben Fry 在 2001 年前后于 MIT Media Lab 发起,语法基于 Java, 但把 Java 里画个圆要写的一堆窗口、缓冲、画笔对象全部包好,只留给你一句 ellipse(320, 180, 80, 80)。

它的几个关键设定

  • 速写本(sketchbook)心智:一个作品 = 一个文件夹 = 一个同名的 .pde 文件。 想到什么就新建一个 sketch 试两笔,不追求"工程结构"。
  • 两个核心函数:setup() 只在程序启动时跑一次; draw() 会被自动反复调用(默认约 60 帧/秒)。所有动画都是"每帧重画一遍"。
  • 坐标系从左上角开始:原点 (0, 0) 在画布左上角,x 向右、y 向下—— 和网页里的 Canvas 一样,和数学课上的直角坐标系不一样。
  • 为设计师和艺术家做的:官方定位是"给不会编程的人学编程,给会编程的人做视觉", 所以生成艺术、数据可视化原型、交互装置、教学演示是它的主场。

同一家人还有:p5.js(JavaScript 版,跑在浏览器里)、 Processing.py(Python 版)、Processing for Android。 Processing 基金会(Processing Foundation)在 2013 年成立,负责维护这一套东西。

二、和 p5.js 的关系

我的理解是:Processing 是源头,p5.js 是它搬到浏览器上的 JavaScript 版本。 p5.js 由 Lauren McCarthy 主导,从 2014 年前后开始发布,目标就是"把 Processing 的速写本搬进网页"。 所以两者的 API 名字几乎完全一样——setup、draw、ellipse、 fill、mouseX、frameCount 全都是同一套。

一样的地方

  • setup() / draw() 的分工一样:初始化一次 + 每帧循环。
  • 坐标系一样:原点左上、y 轴向下;ellipse() 的宽高是直径不是半径。
  • 颜色默认都是 0–255 的 RGB,第四个参数是透明度,也是 0–255。
  • 事件函数名字一样:mousePressed()、keyPressed()、windowResized()。
  • 全局变量一样:mouseX、mouseY、frameCount、width、height。

不一样的地方(迁移时真正要改的)

  • 语言本身:Processing 是 Java(要写类型、要 void);p5.js 是 JavaScript(用 let / const,不写类型)。
  • 建画布:Processing 是 size(640, 360);p5.js 是 createCanvas(640, 360)。
  • 打日志:Processing 用 println() 输出到 IDE 下方控制台;p5.js 用 console.log() 输出到浏览器控制台。
  • 鼠标按下这个布尔量最容易错:Processing 里叫 mousePressed, p5.js 里改叫 mouseIsPressed(因为函数名 mousePressed() 被事件占用了)。
  • 运行环境:Processing 弹出独立窗口、能读写本地文件;p5.js 跑在网页里,受浏览器安全策略限制。

我自己总结的"翻译四步",抄代码的时候照着改基本不会错:

  1. 去掉类型声明:float x = 0; → let x = 0;(int / float 都是 let)。
  2. void setup() → function setup(),draw() 同理。
  3. size(w, h) → createCanvas(w, h),并且留在 setup() 第一行。
  4. println() → console.log(),然后检查有没有用到 mousePressed 这个布尔量。

三、环境搭建

路线 A:装 Processing IDE(桌面版,推荐先走这条)

  1. 去官网 processing.org 的 Download 页,选 Windows 64-bit 版本。 它是个压缩包,解压到任意目录双击里面的 processing.exe 就能用,不需要安装。
  2. 打开后是一个很朴素的编辑器:上面写代码,下面那块是控制台(println() 的内容会出现在这里)。
  3. 点工具栏的 ▶ Run(快捷键 Ctrl+R)运行,会弹出一个独立窗口显示画面; 停止用旁边的 ■ Stop。
  4. 第一次按 Ctrl+S 保存时,Processing 会问你 sketchbook(作品仓库)放哪, 然后自动建好文件夹,例如 sketch_260101a/sketch_260101a.pde。
  5. 命名规则要记住:文件夹名必须和主 .pde 文件名完全一致, 否则这个 sketch 打不开;想改名就用 File → Save As 整包另存,别在资源管理器里手动改。
  6. 想找例子:菜单 File → Examples…,里面按 Topics 分类(Basics、Color、Simulate、Motion…), 挑一个改参数是最快的学法。

两个新手必踩的坑:size() 必须写在 setup() 的第一行,写在别处会报错; 另外 draw() 里如果不先 background() 清屏,上一帧会留在画布上,出来一片"糊掉的重影"。

路线 B:纯网页跑 p5.js(不用装任何东西)

  1. 把 p5.min.js 下载到本地文件夹(建议不要用 CDN:断网或者校园网抽风时,画布会直接空白)。
  2. 新建两个文件:index.html 和 sketch.js,用 <script src="p5.min.js"></script> 和 <script src="sketch.js"></script> 依次引进来。
  3. 在 sketch.js 里写 setup() / draw(),双击 index.html 就能跑 ——画图形、做动画在 file:// 下都没问题。
  4. 查文档看 p5js.org/reference;起步其实只要记住 createCanvas()、background()、ellipse() 三个就够画东西了。

注意一个真实限制:在 file:// 下直接打开网页时,p5 的 loadImage() / loadFont() 会被 Chrome 的跨域策略拦下来(控制台报 CORS)。 解决办法是要么用本地服务器(VS Code 装个 Live Server 插件最省事),要么干脆用普通 <img> 标签加载图片。

四、坐标系与常用函数对照表

两边的坐标系完全一致:原点在画布左上角,x 向右增大,y 向下增大。 下面的表我按"每天都会用到"的顺序排,左边是 Processing 写法,中间是 p5.js 写法。

Processing 与 p5.js 常用函数写法对照表
函数 Processing 写法 p5.js 写法 说明
setup void setup() { ... } function setup() { ... } 程序启动时只执行一次。初始化变量、设置画布都在这里。
draw void draw() { ... } function draw() { ... } 自动循环调用,默认约 60 次/秒。动画就是"每帧重画一遍"。
size / createCanvas size(640, 360); createCanvas(640, 360); 设置画布尺寸(像素)。Processing 里必须是 setup 第一行,且只能设一次。
background background(18, 24, 38); background(18, 24, 38); 用纯色铺满整块画布。写在 draw 开头就等于"擦黑板"。
fill fill(255, 140, 0);
fill(255, 140, 0, 180);
fill(255, 140, 0);
fill(255, 140, 0, 180);
设置填充色,对之后画的形状生效。第四个参数是透明度,0–255。
stroke stroke(120, 200, 255);
strokeWeight(3);
stroke(120, 200, 255);
strokeWeight(3);
描边颜色与粗细,同样只影响"之后画的形状"。
noStroke noStroke(); noStroke(); 关掉描边,只留填充。反过来的开关是 noFill()。
ellipse ellipse(320, 180, 160, 160); ellipse(320, 180, 160, 160); 前两个参数是圆心,后两个是宽和高——注意是直径,不是半径。
rect rect(40, 40, 120, 80); rect(40, 40, 120, 80); 默认以左上角定位。想改成"中心定位"用 rectMode(CENTER)。
line line(0, 0, width, height); line(0, 0, width, height); 起点 x,y + 终点 x,y,一共四个参数。
random float r = random(10, 20); let r = random(10, 20); 返回区间内的随机小数。Processing 里 random(1) 表示 0–1,p5.js 无参 random() 才是 0–1。
frameCount frameCount(int,从 0 开始) frameCount(Number) 已经画了多少帧。做"每隔 N 帧才执行"最方便:frameCount % 30 === 0。
mouseX / mouseY mouseX、mouseY mouseX、mouseY 鼠标在画布内的坐标(相对画布左上角),鼠标移出画布时停在边缘值。
width / height width、height width、height 当前画布宽高。做居中(width / 2)和撞墙反弹时直接拿来用。
mousePressed 布尔量 mousePressed;事件函数 void mousePressed() { } 布尔量 mouseIsPressed;事件函数 function mousePressed() { } 最容易搞混的一对:p5.js 里没有 mousePressed 这个布尔变量,写成 if (mousePressed) 永远是 undefined。
println / 输出 println("x = " + x); console.log("x = " + x); 调试图省事的写法。Processing 输出在 IDE 控制台,p5.js 输出在浏览器 F12 控制台。
text / textSize textSize(20);
text("hi", 20, 40);
textSize(20);
text("hi", 20, 40);
写字。默认以文字左下角定位,想居中用 textAlign(CENTER, CENTER)。
map map(mouseX, 0, width, 60, 255); map(mouseX, 0, width, 60, 255); 把 [0, width] 线性映射到 [60, 255]。用鼠标位置控制颜色、速度、尺寸时特别好用。

表格在窄屏下会自动变成卡片(表头藏起来,每个字段名由 data-label 生成), 所以手机上不需要左右拖动也能读完——这也是我做表格时特意处理的地方。

五、完整可运行示例:撞墙反弹的小球

同一段逻辑写两遍:球在画布里匀速移动,碰到四边就反向; 鼠标的横向位置控制红色通道、纵向位置控制蓝色通道。两版代码逐行对应,可以直接拿去对照。

Processing bouncing_ball.pde 复制进 Processing IDE,按 Ctrl+R 运行
// 撞墙反弹的小球:鼠标位置决定颜色
float x, y;      // 球心坐标
float vx, vy;    // 每一帧移动多少像素(速度)
float r = 26;    // 半径

void setup() {
  size(640, 360);  // 必须写在 setup 的第一行
  noStroke();
  x = width / 2;   // width / height 是画布尺寸,可以直接拿来算居中
  y = height / 2;
  vx = 3.2;
  vy = 2.4;
}

void draw() {
  background(18, 24, 38);   // 每帧先擦黑板,不然会拖出重影

  // 先判断有没有出界,出界就把速度反向(乘 -1),这样就不会卡在墙里
  if (x < r || x > width - r) vx = -vx;
  if (y < r || y > height - r) vy = -vy;

  x = x + vx;
  y = y + vy;

  // map() 把鼠标坐标映射成颜色:横向管红、纵向管蓝
  fill(map(mouseX, 0, width, 60, 255), 140, map(mouseY, 0, height, 255, 90));
  ellipse(x, y, r * 2, r * 2);   // 宽高是直径,所以要乘 2

  fill(255, 255, 255, 170);
  textSize(14);
  text("frameCount: " + frameCount, 16, 24);
}

下面是同一逻辑的 p5.js 版本,连变量名都保持一致,方便左右对照:

p5.js index.html 双击打开即可运行(p5.min.js 需先下到同目录)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>撞墙反弹的小球 · p5.js</title>
  <!-- p5.min.js 下载到本地,不要用 CDN,断网时也能跑 -->
  <script src="p5.min.js"></script>
  <style>
    body { margin: 0; background: #0e1420; display: grid; place-items: center; min-height: 100vh; }
    canvas { display: block; border-radius: 12px; }
  </style>
</head>
<body>
  <script>
    let x, y;        // 球心坐标
    let vx, vy;      // 每帧速度(不再需要声明 float)
    const r = 26;    // 半径

    function setup() {
      createCanvas(640, 360);   // 对应 Processing 的 size()
      noStroke();
      x = width / 2;            // p5 里 width / height 由 createCanvas 设定
      y = height / 2;
      vx = 3.2;
      vy = 2.4;
    }

    function draw() {
      background(18, 24, 38);

      if (x < r || x > width - r) vx = -vx;
      if (y < r || y > height - r) vy = -vy;

      x += vx;
      y += vy;

      fill(map(mouseX, 0, width, 60, 255), 140, map(mouseY, 0, height, 255, 90));
      ellipse(x, y, r * 2, r * 2);

      fill(255, 255, 255, 170);
      textSize(14);
      text('frameCount: ' + frameCount, 16, 24);
    }
  </script>
</body>
</html>

两版之间真正变了什么

  • float x, y; → let x, y;:JavaScript 不写类型。
  • size(640, 360) → createCanvas(640, 360):只有这一句是"必须改"的。
  • x = x + vx → x += vx:只是写法简化,两边都认。
  • 其余绘图逻辑一行没动——这正是 p5.js 的方便之处。

想让它更好玩可以试这几步:把 vy = 2.4 改成 vy = 0 看它掉不下来; 在 draw() 里加一句 r = 20 + sin(frameCount * 0.05) * 8; 让球会呼吸; 或者用 random() 给每次反弹加一点随机扰动。

六、我踩过的坑

  1. size() 写在别处:报错或者尺寸不生效。它必须是 setup() 的第一行。
  2. draw() 里忘了 background():画面越画越糊,看着像显卡坏了,其实是上一帧没擦掉。
  3. 把 ellipse() 的宽高当半径:圆比预想大一倍。半径要自己乘 2。
  4. 文件夹名和 .pde 文件名不一致:Processing 打不开这个 sketch,改名前先想清楚。
  5. 中文注释乱码:老版本 Processing 默认编码不是 UTF-8,要在 Preferences 里把编码设成 UTF-8, 新版本(Processing 4)默认已经没问题了。
  6. p5.js 用 CDN 引脚本:断网、校园网拦截、CDN 抽风,任意一个都会让画布一片空白,还看不到明显报错。 把 p5.min.js 放到本地最稳。
  7. file:// 下 loadImage() 被 CORS 拦:控制台报错但页面不显示图片。 用 Live Server 起个本地服务,或者改用普通 <img>。
  8. 把 mousePressed 当布尔量用在 p5.js 里:应该写 mouseIsPressed, 写成前者会一直拿到 undefined,条件永远不成立。

七、下一步想做什么

  • 把这个反弹小球加上"碰壁时变色 + 留下轨迹",做成一个小画板。
  • 用 random() 和 frameCount 写一个生成艺术小图,导出成 PNG 当作品集封面。
  • 用 p5.js 重写作品集里两个 Canvas 小玩意,对比一下"手写 Canvas"和"用 p5 封装"的差别。
  • 给这份笔记补一个不用联网也能看的离线示例(本地 p5.min.js)。

这份笔记是边学边改的,写法上如果有更简洁的路子,我会直接回来改这一段—— 笔记最好的状态就是被自己反复推翻。