一、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 跑在网页里,受浏览器安全策略限制。
我自己总结的"翻译四步",抄代码的时候照着改基本不会错:
- 去掉类型声明:
float x = 0;→let x = 0;(int/float都是let)。 void setup()→function setup(),draw()同理。size(w, h)→createCanvas(w, h),并且留在setup()第一行。println()→console.log(),然后检查有没有用到mousePressed这个布尔量。
三、环境搭建
路线 A:装 Processing IDE(桌面版,推荐先走这条)
- 去官网
processing.org的 Download 页,选 Windows 64-bit 版本。 它是个压缩包,解压到任意目录双击里面的processing.exe就能用,不需要安装。 - 打开后是一个很朴素的编辑器:上面写代码,下面那块是控制台(
println()的内容会出现在这里)。 - 点工具栏的 ▶ Run(快捷键
Ctrl+R)运行,会弹出一个独立窗口显示画面; 停止用旁边的 ■ Stop。 - 第一次按
Ctrl+S保存时,Processing 会问你 sketchbook(作品仓库)放哪, 然后自动建好文件夹,例如sketch_260101a/sketch_260101a.pde。 - 命名规则要记住:文件夹名必须和主
.pde文件名完全一致, 否则这个 sketch 打不开;想改名就用 File → Save As 整包另存,别在资源管理器里手动改。 - 想找例子:菜单 File → Examples…,里面按 Topics 分类(Basics、Color、Simulate、Motion…), 挑一个改参数是最快的学法。
两个新手必踩的坑:size() 必须写在 setup() 的第一行,写在别处会报错;
另外 draw() 里如果不先 background() 清屏,上一帧会留在画布上,出来一片"糊掉的重影"。
路线 B:纯网页跑 p5.js(不用装任何东西)
- 把
p5.min.js下载到本地文件夹(建议不要用 CDN:断网或者校园网抽风时,画布会直接空白)。 - 新建两个文件:
index.html和sketch.js,用<script src="p5.min.js"></script>和<script src="sketch.js"></script>依次引进来。 - 在
sketch.js里写setup()/draw(),双击index.html就能跑 ——画图形、做动画在file://下都没问题。 - 查文档看
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 写法 | 说明 |
|---|---|---|---|
| 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 生成),
所以手机上不需要左右拖动也能读完——这也是我做表格时特意处理的地方。
五、完整可运行示例:撞墙反弹的小球
同一段逻辑写两遍:球在画布里匀速移动,碰到四边就反向; 鼠标的横向位置控制红色通道、纵向位置控制蓝色通道。两版代码逐行对应,可以直接拿去对照。
// 撞墙反弹的小球:鼠标位置决定颜色
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 版本,连变量名都保持一致,方便左右对照:
<!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() 给每次反弹加一点随机扰动。
六、我踩过的坑
size()写在别处:报错或者尺寸不生效。它必须是setup()的第一行。draw()里忘了background():画面越画越糊,看着像显卡坏了,其实是上一帧没擦掉。- 把
ellipse()的宽高当半径:圆比预想大一倍。半径要自己乘 2。 - 文件夹名和
.pde文件名不一致:Processing 打不开这个 sketch,改名前先想清楚。 - 中文注释乱码:老版本 Processing 默认编码不是 UTF-8,要在 Preferences 里把编码设成 UTF-8, 新版本(Processing 4)默认已经没问题了。
- p5.js 用 CDN 引脚本:断网、校园网拦截、CDN 抽风,任意一个都会让画布一片空白,还看不到明显报错。
把
p5.min.js放到本地最稳。 file://下loadImage()被 CORS 拦:控制台报错但页面不显示图片。 用 Live Server 起个本地服务,或者改用普通<img>。- 把
mousePressed当布尔量用在 p5.js 里:应该写mouseIsPressed, 写成前者会一直拿到undefined,条件永远不成立。
七、下一步想做什么
- 把这个反弹小球加上"碰壁时变色 + 留下轨迹",做成一个小画板。
- 用
random()和frameCount写一个生成艺术小图,导出成 PNG 当作品集封面。 - 用 p5.js 重写作品集里两个 Canvas 小玩意,对比一下"手写 Canvas"和"用 p5 封装"的差别。
- 给这份笔记补一个不用联网也能看的离线示例(本地 p5.min.js)。
这份笔记是边学边改的,写法上如果有更简洁的路子,我会直接回来改这一段—— 笔记最好的状态就是被自己反复推翻。