
1. 从“画个圈”开始为什么选择p5.js作为编程第一课如果你对编程感兴趣但又觉得打开一个黑漆漆的命令行或者面对一堆枯燥的语法规则就头大那我建议你试试p5.js。它不是一个严肃的工业级框架而是一个能让你在浏览器里“玩”起来的创意编程库。我第一次接触它是因为想给一个枯燥的数据报告加点动态图表结果一上手就发现这玩意儿太适合用来建立编程的“手感”和“正反馈”了。简单来说p5.js让你用写代码的方式画画、做动画、甚至做交互。它的核心哲学是“草图”Sketch把编程看作一种艺术创作。你不用先去理解复杂的“面向对象”、“设计模式”而是从最直观的视觉反馈开始写几行代码画布上就出现一个圆改几个数字圆就动了起来。这种即时、可视的成就感是学习编程初期最宝贵的动力来源。很多人在学习Python或JavaScript基础时常常在控制台里打印“Hello World”后就感到迷茫不知道接下来能做什么。p5.js直接跳过了这个阶段让你从一开始就在创造看得见、摸得着的东西。从技术栈上看p5.js基于JavaScript这意味着你学会的每一行代码都是未来可以用于网页开发、后端服务Node.js甚至游戏开发的真实技能。它帮你平滑地过渡到更广泛的JavaScript生态。而且它的社区充满了艺术家、设计师和教育者教程和案例往往更具创意和启发性能让你看到代码除了做业务逻辑之外的另一种可能性——表达与创造。2. 零基础搭建你的第一个“数字画布”别被“环境搭建”吓到用p5.js你甚至不需要安装任何软件。最快捷的方式是使用它的官方在线编辑器。打开浏览器访问 p5js.org点击“开始”菜单下的“在线编辑器”你就会进入一个已经为你配置好的编码环境。左边是代码区右边是实时预览的画布。这种方式完全避免了本地安装Node.js、配置编辑器的麻烦让你在10秒内就能开始编码。当然如果你希望有一个更持久、更个性化的本地环境步骤也非常简单。本质上你只需要一个文本编辑器比如VS Code、Sublime Text甚至记事本和一个浏览器。新建一个HTML文件比如index.html在里面写入以下结构!DOCTYPE html html langzh head meta charsetUTF-8 title我的第一个p5.js草图/title script srchttps://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js/script /head body script srcsketch.js/script /body /html然后在同目录下创建一个sketch.js文件。这个文件就是你写p5.js代码的地方。用浏览器打开这个index.html文件你就能看到运行结果。这里的关键是第7行我们从CDN引入了p5.js库这样你就不需要下载任何文件。注意在线编辑器适合快速尝试和分享而本地环境更适合做正式的项目和版本管理。我建议初学者先从在线编辑器上手找到感觉后再迁移到本地。在sketch.js里p5.js程序通常围绕两个核心函数构建setup()和draw()。setup()函数只在程序启动时运行一次用于初始化设置比如创建画布。draw()函数则会以每秒约60帧的频率反复运行用于制作动画和实现交互。我们来写一个最基础的例子function setup() { createCanvas(400, 400); // 创建一个400像素宽400像素高的画布 background(220); // 将画布背景设置为浅灰色 (RGB值220) } function draw() { ellipse(200, 200, 50, 50); // 在坐标(200,200)处画一个宽高均为50的椭圆即圆形 }把这段代码保存到sketch.js刷新浏览器你就能在画布中央看到一个灰色的圆形。恭喜你已经完成了编程入门的第一步——让计算机执行了你的第一条指令。这里的createCanvas、background、ellipse都是p5.js提供的函数你可以把它们理解为给计算机的“绘画命令”。3. 理解坐标系、图形与颜色的编程逻辑画出了一个圆你可能想我怎么控制它的大小、位置和颜色这就涉及到编程中最基础也最重要的概念之一坐标系和函数参数。在p5.js的画布上左上角是原点(0, 0)。X轴向右延伸Y轴向下延伸。所以ellipse(200, 200, 50, 50)中的前两个数字200, 200就代表圆心的坐标从左边往右200像素从上往下200像素。后两个数字50, 50分别代表椭圆的宽度和高度。如果你想画一个在左上角的小圆可以写成ellipse(50, 50, 30, 30)。颜色在p5.js中通常用RGB红绿蓝或HSB色相饱和度亮度模式来定义。最常用的fill()函数用于设置图形的填充色stroke()用于设置图形边框的颜色strokeWeight()用于设置边框粗细。在设置颜色后之后绘制的所有图形都会沿用这个颜色直到你再次改变它。function setup() { createCanvas(400, 400); background(255); // 白色背景 } function draw() { noStroke(); // 取消边框 fill(255, 0, 0); // 设置为纯红色 (R255, G0, B0) ellipse(100, 200, 80, 80); // 画一个红色的圆 stroke(0, 0, 255); // 设置边框为蓝色 strokeWeight(4); // 边框粗细为4像素 noFill(); // 不填充内部 ellipse(300, 200, 80, 80); // 画一个只有蓝色边框的空心圆 }这段代码会画出两个风格迥异的圆。理解参数传递的顺序和意义是读懂和编写任何代码的基础。你可以把函数想象成一个机器你按照说明书文档把原料参数按顺序放进去它就会产出你想要的结果。实操心得在修改颜色或样式时很容易忘记这些设置是“全局状态”。比如你设置了红色填充之后画的所有形状都会是红色除非你再次用fill()改变它。一个良好的习惯是在绘制每个独立图形前都明确地设置一遍它的样式属性这样可以避免意料之外的样式污染。4. 让画面动起来变量、循环与动画原理静态的图形只是开始让它们动起来编程的逻辑魅力才真正展现。动画的本质是在每一帧即每次draw()函数执行时轻微地改变物体的某个属性如位置、颜色、大小。要实现这个我们需要变量。变量就像是一个贴了标签的盒子你可以把数据比如一个数字放进去之后通过标签名来使用或修改这个数据。在draw()函数外声明一个变量它的值就可以在每一帧中被访问和修改。let circleX 50; // 声明一个变量circleX初始值为50 function setup() { createCanvas(400, 400); } function draw() { background(220); // 每一帧都重绘背景擦除上一帧的痕迹 ellipse(circleX, 200, 50, 50); // 圆的X坐标使用变量circleX circleX circleX 1; // 每一帧让circleX的值增加1 }运行这段代码你会看到圆从左侧慢慢向右移动。因为每一帧draw()执行时我们都用新的circleX值比上一帧大1来画圆然后清空背景视觉上就形成了连续的运动。background(220)在draw()里非常重要它清除了上一帧的画面否则你会看到圆移动后留下的一长串轨迹。如果想让圆到达边界后反弹就需要引入条件判断。我们可以检查circleX是否超过了画布宽度如果超过了就让它反向移动。let circleX 50; let speed 2; // 再声明一个变量表示速度 function setup() { createCanvas(400, 400); } function draw() { background(220); ellipse(circleX, 200, 50, 50); circleX circleX speed; // 用速度变量来改变位置 // 如果圆碰到了右边界圆心X坐标半径 画布宽度或左边界圆心X坐标-半径 0 if (circleX width - 25 || circleX 25) { speed speed * -1; // 将速度反向实现反弹 } }这里用到了width这个p5.js内置的变量它代表了画布的宽度。if语句是编程中的条件判断它让代码有了“决策”能力。这个简单的动画包含了变量、循环draw的反复执行、条件判断这三个编程核心概念它们构成了几乎所有复杂程序的基础。5. 与你的作品互动鼠标与键盘事件交互能让你的作品从“动画”升级为“体验”。p5.js提供了非常简便的方式来获取鼠标和键盘的状态。内置变量mouseX和mouseY实时存储着鼠标光标在画布上的坐标。你可以直接用它们来控制图形。function setup() { createCanvas(400, 400); noStroke(); } function draw() { background(220, 50); // 这里给背景色加了一个透明度参数50会产生拖尾效果 // 用鼠标位置控制一个圆 fill(255, 0, 0, 150); // 红色带150的透明度 ellipse(mouseX, mouseY, 60, 60); // 在固定位置画另一个圆但其大小受鼠标位置影响 let diameter dist(mouseX, mouseY, 200, 200); // 计算鼠标到点(200,200)的距离 fill(0, 0, 255, 150); ellipse(200, 200, diameter/2, diameter/2); // 用距离的一半作为圆的直径 }这个例子中一个红色的圆会紧紧跟随你的鼠标而画布中心的蓝色圆则会根据你鼠标离中心的远近改变大小。dist()是p5.js提供的计算两点间距离的函数。通过组合这些基本的交互元素你已经可以做出有趣的动态效果了。除了持续跟踪p5.js还提供了事件函数如mousePressed()、keyPressed()它们只在特定事件发生时被调用一次。比如我们可以实现点击鼠标就在点击位置画一个圆function setup() { createCanvas(400, 400); background(255); } function draw() { // draw函数可以空着因为我们只在点击时画画 } function mousePressed() { fill(random(255), random(255), random(255)); // 随机颜色 ellipse(mouseX, mouseY, 30, 30); }random(255)会生成一个0到255之间的随机数用于产生随机的RGB颜色值。每次点击都会在鼠标位置画一个随机颜色的圆。这种基于事件的编程模式在网页开发如点击按钮和游戏开发如按下空格键跳跃中无处不在。6. 从模仿到创造分析一个经典案例“动态粒子背景”学习编程尤其是创意编程最好的方法之一就是研究优秀的案例然后拆解、模仿、再创新。网上有很多用p5.js做的炫酷粒子系统、生成艺术。我们来拆解一个相对简单的“动态粒子背景”理解其背后的编程思路。这个效果通常包含以下元素一群粒子小圆点每个粒子有位置、速度、大小等属性粒子会缓慢移动当两个粒子距离足够近时它们之间会画一条线形成网状结构。首先我们需要用数组来管理一群粒子。数组就像一个有多层格子的柜子可以按顺序存放很多个数据在这里是很多个粒子对象。每个粒子我们可以用一个简单的对象来表示包含它的坐标和移动速度。let particles []; // 声明一个空数组用于存放所有粒子 function setup() { createCanvas(windowWidth, windowHeight); // 画布铺满整个窗口 // 初始化创建一定数量的粒子 for (let i 0; i 100; i) { particles[i] { x: random(width), y: random(height), vx: random(-1, 1), // X方向速度在-1到1之间随机 vy: random(-1, 1) // Y方向速度 }; } } function draw() { background(0, 20); // 用带透明度的黑色背景产生拖尾模糊效果 // 更新并绘制每一个粒子 for (let i 0; i particles.length; i) { let p particles[i]; // 取出第i个粒子 // 更新位置 p.x p.vx; p.y p.vy; // 边界检查让粒子在画布内反弹 if (p.x 0 || p.x width) p.vx * -1; if (p.y 0 || p.y height) p.vy * -1; // 绘制粒子本身 fill(255); noStroke(); ellipse(p.x, p.y, 4, 4); // 检查与其他粒子的距离 for (let j i 1; j particles.length; j) { let other particles[j]; let d dist(p.x, p.y, other.x, other.y); // 计算距离 if (d 100) { // 如果距离小于100像素 stroke(255, 255 - d*2); // 画线距离越远线越透明 line(p.x, p.y, other.x, other.y); } } } }这段代码包含了几个关键点数据结构用对象{}来组织一个粒子的多个属性x, y, vx, vy用数组[]来管理所有粒子。循环嵌套外层循环遍历每个粒子以更新和绘制它内层循环for (let j i 1; ...)让当前粒子只与它后面的粒子计算距离避免重复计算A和B算一次就不要再算B和A了。算法优化粒子间连线需要计算两两距离这是一个计算量较大的操作复杂度O(n²)。当粒子数量很多时比如超过1000可能会造成卡顿。在实际项目中可能会采用空间划分算法如四叉树来优化。但对于入门学习和视觉效果来说100个粒子左右完全足够流畅。你可以尝试修改代码中的参数background(0, 20)中的透明度20、粒子数量100、连线阈值100、粒子速度范围random(-1, 1)。每一个参数的改变都会让最终效果产生巨大变化这就是参数化创作的乐趣。踩坑实录在draw()函数中如果不使用带透明度的背景background(0, 20)而是用完全不透明的背景background(0)那么每一帧都会完全清除画布粒子移动的轨迹即连线就不会保留你将看不到网状结构只能看到一个个孤立的点在跳动。这个“拖尾”效果是许多动态视觉作品的常用技巧其本质是每一帧不完全擦除上一帧的内容。7. 当代码变复杂如何组织、调试与寻找灵感当你的草图代码超过一百行各种变量和函数开始交织时良好的代码组织习惯就变得至关重要。这不仅能让你自己日后能看懂也便于分享和协作。7.1 代码组织建议使用函数封装功能如果你有一段代码负责绘制一棵树或者处理一种特定的交互把它写成一个独立的函数。例如function drawTree(x, y, size) { // 绘制树干和树枝的代码... }这样在draw()里只需要调用drawTree(100, 300, 50)主逻辑会清晰很多。合理使用注释在关键步骤、复杂的算法或者你容易忘记的地方写上注释。注释不是越多越好而是解释“为什么这么做”而不是“做了什么”代码本身已经说明了做什么。变量命名要有意义使用circleRadius而不是r使用particleList而不是arr。清晰的命名是最好的文档。7.2 调试技巧编程中出错是家常便饭p5.js提供了简单的调试方法。console.log()是你的好朋友在浏览器中按F12打开开发者工具切换到“控制台”Console标签。在代码中插入console.log(变量名)可以在控制台打印出该变量的值帮助你理解程序运行到某一步时数据是什么样子。比如在粒子系统中你可以console.log(p.x)来跟踪某个粒子的位置。利用浏览器调试器在开发者工具的“源代码”Sources标签中你可以找到你的sketch.js文件在行号上点击可以设置断点。当代码执行到断点时程序会暂停你可以查看此时所有变量的值并一步步执行代码这是定位复杂逻辑错误的利器。7.3 寻找灵感与深入学习当你掌握了基础可能会遇到“接下来做什么”的瓶颈。以下是一些寻找灵感和资源的途径p5.js官方网站其“示例”Examples和“参考”Reference页面是无价之宝。参考页面是所有函数的详细说明书遇到不熟悉的函数就去查。开源社区GitHub、CodePen、OpenProcessing 等网站上有海量p5.js作品很多都附带了完整的源代码。尝试去“复刻”你喜欢的效果是极佳的学习方式。跳出绘图p5.js不仅可以绘图还能处理声音p5.sound库、视频、摄像头输入、甚至连接硬件通过串口或网络。尝试用麦克风音量控制图形大小或者用摄像头画面作为互动元素会打开新世界的大门。学习基础计算机图形学概念当你对简单的图形运动感到不满足时可以了解一些基础概念如向量p5.js内置了p5.Vector类、力模拟物理、噪声函数noise()用于生成更自然的随机运动等。这些知识能让你创造出更复杂、更有机的效果。从在画布上画出一个静止的圆到创造出拥有数百个互动粒子的动态系统这个过程正是编程学习的一个缩影从具体指令到抽象思维从模仿到创造。p5.js的魅力在于它把编程中那些看似枯燥的概念——变量、循环、函数、数组、对象——都包裹在了即时、可视、有趣的视觉反馈之中。当你通过修改几个数字就让整个作品的气质发生改变时你会真切地感受到代码作为一种创作媒介的力量。这种正反馈是支撑你深入更广阔、也更复杂的编程世界的最强动力。