news 2026/7/28 10:45:44

p5.js创意编程入门:用JavaScript代码绘制交互式动画与图形

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
p5.js创意编程入门:用JavaScript代码绘制交互式动画与图形

1. 项目概述:为什么选择p5.js作为编程的“第一支画笔”?

如果你对编程世界充满好奇,但又觉得那些黑底白字的命令行、复杂的语法规则和抽象的逻辑概念像一堵高墙,那么,p5.js可能就是为你打开的那扇窗。它不是又一个枯燥的语法教程,而是一个让你能立刻看到“代码如何创造世界”的游乐场。简单来说,p5.js是一个基于JavaScript的创意编程库,它的核心哲学是“让代码成为艺术家的画笔,让编程成为创意的延伸”。我最初接触它,是因为厌倦了传统入门教程里那些“Hello World”和计算器项目——它们固然重要,但缺乏即时的、视觉化的正向反馈,很容易消磨初学者的热情。而p5.js,你写几行代码,画布上就能立刻出现一个会动的圆圈、一片渐变的色彩,甚至是一个交互式的游戏,这种所见即所得的魔力,是保持学习动力的最佳燃料。

对于零基础的朋友,它友好到令人发指:你只需要一个浏览器和一个文本编辑器(甚至记事本都行),就能开始创作。对于有少许HTML/CSS经验的前端爱好者,它能帮你平滑过渡到JavaScript的动态逻辑世界。而对于设计师或艺术背景的从业者,它则是一座连接创意与技术的坚实桥梁。这个项目的核心价值,就是用“绘图”这个直观、有趣的动作作为切入点,带你无痛踏入编程的大门,理解变量、函数、循环、条件判断这些核心概念是如何协同工作,最终创造出令人惊叹的视觉作品的。接下来,我会带你从零开始,亲手用代码“画”出第一个图形,并逐步拆解背后的编程思维,让你不仅学会“画”,更理解“为什么这么画”。

2. 环境搭建与第一个图形:从“零”到“一”的魔法时刻

2.1 极简开发环境搭建:告别复杂配置

很多编程入门的第一道坎,就是繁琐的环境配置:安装IDE、配置SDK、设置环境变量……还没开始写代码,热情就先被浇灭了一半。p5.js彻底颠覆了这一点。你有两种几乎零成本的方式可以开始:

方案一:使用官方在线编辑器(最推荐新手)直接访问 p5.js 的官方网站,找到“在线编辑器”(p5.js Web Editor)。这是一个完全在浏览器中运行的集成环境。它的优势极其明显:

  1. 零安装:打开即用,无需在本地安装任何软件。
  2. 内置参考:侧边栏有完整的函数库文档,鼠标悬停即可查看说明,堪比随身的编程词典。
  3. 一键运行:写完代码点击播放按钮,结果立刻在右侧画布呈现。
  4. 项目分享:可以一键生成链接分享你的作品,方便向他人展示或求助。

方案二:本地纯文本文件(理解Web本质)如果你想知道这一切是如何在本地运行的,只需三步:

  1. 在你的电脑上新建一个文件夹,命名为myFirstP5
  2. 在这个文件夹里,新建一个文本文档,将其重命名为sketch.js注意:务必确保文件扩展名从.txt变成了.js(如果看不到扩展名,需要在系统设置中打开“显示文件扩展名”)。
  3. 再新建一个文本文档,重命名为index.html。用记事本或任何文本编辑器打开它,输入以下最简化的HTML结构:
<!DOCTYPE html> <html> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script> </head> <body> <script src="sketch.js"></script> </body> </html>

保存后,直接用浏览器双击打开这个index.html文件。浏览器会从网络加载p5.js库,并执行你的sketch.js文件。恭喜你,你已经搭建好了一个完整的本地开发环境!这种方式让你直观地理解了网页是如何引用外部JavaScript库的。

注意:在本地文件方式下,如果你在代码中加载了本地图片或字体文件,部分浏览器(如Chrome)会因为安全策略(CORS)而阻止。这时,一个简单的解决办法是使用VSCode的“Live Server”插件,它会启动一个本地服务器来绕过这个限制。对于纯图形绘制入门,我们暂时用不到外部文件,所以直接双击打开HTML文件即可。

2.2 理解p5.js的程序骨架:setup()draw()

打开你的sketch.js文件(或在在线编辑器中),我们将开始编写第一行代码。p5.js程序有两个最核心的函数,它们构成了所有动画和交互的骨架:

  • setup()函数:顾名思义,是“设置”阶段。这个函数在程序启动时只执行一次。通常在这里定义画布大小、设置初始背景色、加载资源等一次性工作。
  • draw()函数:是“绘制”阶段。在setup()执行完毕后,draw()函数会以每秒约60帧的速度反复、循环执行。所有动画效果、持续的视觉变化和交互响应,都是通过在这个函数中不断重绘画布来实现的。

让我们写下第一个有结构的程序:

function setup() { // 创建一个400像素宽,300像素高的画布 createCanvas(400, 300); // 将画布的背景色设置为浅灰色(RGB值) background(220); } function draw() { // 目前draw函数是空的,所以画布静止不动 // 后续的动画和交互代码将主要写在这里 }

将这段代码复制到你的编辑器中并运行,你会看到一个静止的浅灰色矩形画布。createCanvas(400, 300)就像是给你准备了一张400x300的画纸,而background(220)则是给这张纸刷上了一层底色。draw()函数虽然空着,但它已经在后台高速运转了,只是我们还没让它“画”任何东西。

2.3 绘制第一个图形:理解坐标系统

现在,让我们在draw()函数里画点东西。在绘图之前,必须理解p5.js(以及绝大多数计算机绘图)的坐标系统:原点(0,0)在画布的左上角,X轴向右为正方向,Y轴向下为正方向。这和你数学课上学的坐标系Y轴向上不同,需要一点时间来适应。

我们在draw()函数中添加一个圆形:

function draw() { // 在坐标 (200, 150) 的位置,绘制一个直径为100的圆 circle(200, 150, 100); }

运行代码,你会在画布正中央看到一个黑色的空心圆。circle(x, y, d)函数的三个参数分别代表了圆心的X坐标、Y坐标和直径。因为我们的画布是400x300,所以中心点坐标就是(200, 150)。

但这还不够酷,它只是个静止的黑色轮廓。让我们给它加点颜色和动态效果。修改draw()函数如下:

function draw() { // 每次循环都先用半透明的白色覆盖整个画布,产生拖尾效果 background(220, 220, 220, 10); // 将填充色设置为红色(RGB: 255, 0, 0) fill(255, 0, 0); // 将描边色设置为黄色,描边粗细为5像素 stroke(255, 255, 0); strokeWeight(5); // 让圆的位置跟随鼠标移动!mouseX和mouseY是p5.js提供的系统变量,代表当前鼠标坐标 circle(mouseX, mouseY, 100); }

再次运行,奇迹发生了!你得到了一个跟着鼠标移动的、红底黄边的圆,而且因为background设置了透明度(第四个参数10代表很低的透明度),圆移动的轨迹会慢慢淡去,形成漂亮的拖尾效果。这就是编程的即时反馈:短短几行代码,你就创造了一个交互式动画。fill()stroke()strokeWeight()这些函数,就像你在调色板和选择画笔粗细,而mouseXmouseY这两个神奇的变量,则把用户的输入(鼠标移动)无缝接入到了你的程序中。

3. 核心概念拆解:用绘图理解编程语法

通过第一个动起来的圆,你已经无意中使用了几个核心编程概念。现在,让我们把这些概念从“感觉”上升到“理解”。

3.1 变量:数据的“储物盒”

变量是编程中最基础的概念,你可以把它理解为一个贴了名字的储物盒,里面可以存放一个数据(数字、文字、颜色等)。在刚才的例子里,mouseXmouseY就是p5.js预定义好的变量,它们实时存储着鼠标的坐标。我们也可以创建自己的变量。

假设我们不想让圆的直径固定为100,而是想让它随着时间变化。我们可以这样做:

let circleSize = 50; // 声明一个名为circleSize的变量,并赋初始值50 function setup() { createCanvas(400, 300); } function draw() { background(220); fill(100, 200, 255); // 一种蓝色 noStroke(); // 取消描边 // 在draw函数中改变变量的值,让它每帧增加0.5 circleSize = circleSize + 0.5; // 如果圆的直径超过200,就重置为50,实现循环变大变小的效果 if (circleSize > 200) { circleSize = 50; } // 使用变量作为圆的直径参数 circle(width / 2, height / 2, circleSize); }

这里,let circleSize = 50;声明了一个变量。circleSize = circleSize + 0.5;是让变量在自身基础上增加0.5(这行代码可以简写为circleSize += 0.5;)。if (circleSize > 200) { ... }是一个条件判断,当条件成立时,执行大括号里的重置命令。widthheight是p5.js提供的另外两个系统变量,代表画布的宽和高,width / 2就是画布中心的X坐标。通过一个自定义变量,我们实现了图形的动态变化。

3.2 函数:可重复使用的“技能包”

函数是一段被命名的、可重复使用的代码块。circle(),fill(),background()这些都是p5.js内置的函数,我们调用它们来完成特定任务。我们也可以定义自己的函数来组织代码,让逻辑更清晰。

比如,我们要画一个由多个部分组成的“笑脸”,每次都写一遍所有绘制命令会很繁琐。我们可以把它封装成一个函数:

function drawSmiley(x, y, size) { // 画脸(一个大圆) fill(255, 255, 0); // 黄色脸 stroke(0); strokeWeight(2); circle(x, y, size); // 画左眼 fill(0); noStroke(); circle(x - size/5, y - size/10, size/10); // 画右眼 circle(x + size/5, y - size/10, size/10); // 画嘴巴(一段弧线) stroke(0); strokeWeight(3); noFill(); arc(x, y + size/10, size/2, size/3, 0, PI); // arc画弧线,参数依次是:中心x,y, 宽度,高度, 起始弧度, 结束弧度 } function setup() { createCanvas(600, 400); } function draw() { background(180); // 调用三次自定义函数,画出三个不同位置、大小的笑脸 drawSmiley(150, 200, 120); drawSmiley(300, 200, 80); drawSmiley(450, 200, 150); }

function drawSmiley(x, y, size) { ... }定义了一个名为drawSmiley的函数,它需要三个参数:笑脸中心的x坐标、y坐标和整体大小。在draw()里,我们只需一行drawSmiley(150, 200, 120);就能在指定位置画出一个完整的笑脸。通过改变传入的参数,我们轻松地画出了三个不同的笑脸。函数极大地提高了代码的复用性和可读性。

3.3 循环:让计算机替你“重复劳动”

循环用于自动重复执行某段代码。想象你要在画布上画100个随机位置、随机颜色的圆,用手写100次circle()是不可能的。这时就需要循环。

function setup() { createCanvas(800, 600); background(0); // 黑色背景 noStroke(); // 使用for循环:声明一个计数器i;循环条件是i<500;每循环一次,i增加1 for (let i = 0; i < 500; i++) { // 为每个圆生成随机位置和颜色 let x = random(width); // random(width) 生成一个0到画布宽度之间的随机数 let y = random(height); let r = random(255); // 红色分量随机 let g = random(255); // 绿色分量随机 let b = random(255); // 蓝色分量随机 let alpha = random(100, 255); // 透明度随机 let size = random(5, 30); // 大小随机 // 设置填充色(带透明度) fill(r, g, b, alpha); // 在随机位置画圆 circle(x, y, size); } } function draw() { // draw函数为空,只生成一次静态图像 }

这段代码在setup()中运行一次,但内部的for循环执行了500次。每次循环,i的值从0递增到499,循环体内的代码就会执行一次,生成一组随机参数并画一个圆。最终,我们得到了一个由500个随机圆点构成的抽象画。random()是p5.js中非常重要的函数,它能产生随机数,为作品带来不确定性和生命力。循环是自动化、批量处理的核心,也是理解算法效率的起点。

4. 进阶交互与动画:让你的作品“活”起来

静态图像很美,但交互和动画才是p5.js的灵魂。我们已经用到了mouseX/mouseY实现跟随,现在来探索更丰富的交互事件和动画原理。

4.1 响应鼠标与键盘事件

p5.js提供了一系列以mousekey开头的事件函数,它们只在特定事件发生时被调用一次,而不是像draw()那样持续运行。

let backgroundColor; // 声明一个变量用于存储背景色 function setup() { createCanvas(400, 400); backgroundColor = color(200); // 初始化为灰色 } function draw() { background(backgroundColor); fill(0, 150, 255); // 画一个始终在画布中心的圆 circle(width/2, height/2, 100); } // 当鼠标在画布上按下时,此函数被调用一次 function mousePressed() { // 随机生成一个颜色 backgroundColor = color(random(255), random(255), random(255)); console.log('鼠标按下!背景色已改变。'); // 在浏览器控制台输出信息,用于调试 } // 当键盘上的键被按下时,此函数被调用一次 function keyPressed() { if (key === ' ') { // 如果按下的键是空格键 saveCanvas('myArtwork', 'png'); // 将当前画布保存为名为“myArtwork.png”的图片 console.log('画布已保存!'); } // 可以添加更多按键判断,如 key === 'a' 等 }

在这个例子中,draw()负责持续的绘制(一个静止的圆)。交互逻辑则由事件函数mousePressed()keyPressed()处理。点击画布任意位置,背景色会随机变化;按下空格键,会自动下载当前画面的截图。事件驱动编程是图形交互应用的基础,它让你的程序能够响应用户的主动操作。

4.2 实现平滑动画:基于时间的状态变化

真正的动画不仅仅是让物体移动,还要让移动看起来平滑、自然。这通常需要基于时间(帧数)来更新物体的状态(位置、大小、颜色等)。

我们来制作一个匀速来回弹跳的小球:

let xPos = 50; // 小球的初始X位置 let speed = 3; // 小球的水平速度(像素/帧) let diameter = 40; // 小球直径 function setup() { createCanvas(600, 200); } function draw() { background(240); // 更新小球位置 xPos = xPos + speed; // 边界检测:当小球碰到右边缘或左边缘时,反转速度方向 if (xPos > width - diameter/2) { // 右边缘:画布宽度减去半径 speed = -speed; // 速度变为负值,向左运动 xPos = width - diameter/2; // 防止小球卡在边界外 } else if (xPos < diameter/2) { // 左边缘:半径位置 speed = -speed; // 速度变为正值,向右运动 xPos = diameter/2; } // 绘制小球 fill(255, 100, 100); noStroke(); circle(xPos, height/2, diameter); }

动画的核心逻辑在draw()的更新部分。每一帧,我们都用xPos = xPos + speed;来根据速度更新小球的位置。if条件判断用于检测小球是否碰到了画布左右边缘,如果碰到,就将速度speed乘以 -1,从而实现反向运动。这个“更新位置 -> 检测碰撞 -> 响应碰撞”的循环,是游戏和交互动画中最基本的模式之一。你可以尝试修改speed的初始值,或者加入重力、加速度等物理因素,让动画更复杂。

4.3 使用三角函数创造复杂运动

直线运动有些单调,三角函数(sin,cos)可以帮助我们创造出优美的周期性运动,比如波浪、圆周运动或缓动效果。

let angle = 0; // 角度变量,用于三角函数输入 function setup() { createCanvas(800, 300); noStroke(); } function draw() { background(0); fill(100, 220, 255); // 使用sin函数产生Y坐标的周期性变化 // sin(angle)的值在-1到1之间波动 // 将其映射到画布上一个合适的范围,比如 height/4 到 3*height/4 let y = height/2 + sin(angle) * 100; // 在画布中心画一个随正弦波上下移动的圆 circle(width/2, y, 60); // 绘制一条由许多小圆组成的正弦波 for (let x = 0; x < width; x += 10) { // 每个小圆的x坐标固定,y坐标由sin函数决定,并且加入x值来产生相位差 let waveY = height/2 + sin(angle + x * 0.05) * 50; circle(x, waveY, 8); } // 每一帧增加角度值,角度变化的速度决定了波动的快慢 angle += 0.05; }

sin(angle)函数会根据angle的值返回一个平滑的、在-1到1之间循环的值。通过将这个值乘以一个振幅(如100),再加上一个基准值(如height/2),我们就得到了一个在固定范围内上下波动的Y坐标。在循环中,我们为每个小圆的X坐标加入一个相位差(x * 0.05),使得整条波浪看起来是连续的。缓慢增加angle变量,就产生了波浪向前推进的动画效果。三角函数是创造自然、有机运动形态的利器。

5. 从模仿到创作:项目实战与灵感拓展

掌握了基础,我们就可以尝试组合这些元素,完成一些有趣的小项目。这是从“学习语法”到“解决问题”的关键一步。

5.1 项目实战:交互式粒子系统

粒子系统是图形学中的经典概念,用来模拟烟雾、火焰、星空、流体等效果。我们来实现一个简单的鼠标交互粒子系统。

let particles = []; // 用一个数组来存储所有的粒子对象 function setup() { createCanvas(800, 600); // 初始化时创建一些粒子 for (let i = 0; i < 100; i++) { particles.push(new Particle(random(width), random(height))); } } function draw() { // 用带透明度的黑色做背景,产生拖尾/淡出效果 background(0, 10); // 遍历并更新、显示每一个粒子 for (let p of particles) { p.update(); p.display(); p.checkEdge(); // 检查边界 } // 如果鼠标被拖动,在鼠标位置添加新粒子 if (mouseIsPressed) { for (let i = 0; i < 3; i++) { // 一次添加多个,效果更密集 particles.push(new Particle(mouseX, mouseY)); } // 限制粒子总数,避免性能下降 if (particles.length > 500) { particles.splice(0, 10); // 如果超过500个,就从数组开头移除10个 } } } // 定义一个“粒子”类(Class),这是面向对象编程的思想,将粒子的数据和功能封装在一起 class Particle { constructor(x, y) { this.pos = createVector(x, y); // 位置,使用p5.Vector对象便于进行向量运算 this.vel = p5.Vector.random2D(); // 速度,一个随机的二维向量 this.vel.mult(random(1, 3)); // 给随机速度一个大小 this.acc = createVector(0, 0); // 加速度,初始为0 this.lifetime = 255; // 粒子生命周期(透明度) this.size = random(3, 8); // 粒子大小 this.color = color(random(200,255), random(100,200), random(200,255)); // 随机颜色 } update() { // 让粒子受到一个微弱的随机力(模拟空气扰动) let wind = createVector(random(-0.01, 0.01), random(-0.01, 0.01)); this.acc.add(wind); // 物理模拟:速度改变位置,加速度改变速度 this.vel.add(this.acc); this.pos.add(this.vel); // 重置加速度 this.acc.mult(0); // 生命衰减 this.lifetime -= 1; } display() { noStroke(); fill(red(this.color), green(this.color), blue(this.color), this.lifetime); // 颜色随生命周期变透明 circle(this.pos.x, this.pos.y, this.size); } checkEdge() { // 如果粒子飞出画布,就让它从对侧回来 if (this.pos.x > width) this.pos.x = 0; if (this.pos.x < 0) this.pos.x = width; if (this.pos.y > height) this.pos.y = 0; if (this.pos.y < 0) this.pos.y = height; } isFinished() { // 判断粒子生命是否结束 return this.lifetime < 0; } }

这个项目综合运用了数组、循环、自定义类(Class)、向量运算、随机数和交互事件。Particle类定义了一个粒子的所有属性和行为。在draw()中,我们管理一个粒子数组,不断更新和绘制它们。鼠标拖动会添加新粒子,同时系统会限制总粒子数以保证性能。运行后,你会看到一片飘动的粒子,拖动鼠标可以“绘制”出新的粒子流。这个项目虽然代码量稍多,但结构清晰,是学习如何组织复杂代码的绝佳范例。

5.2 灵感拓展与资源指引

当你完成上述项目后,可以尝试以下方向进行拓展,将p5.js应用到更广阔的领域:

  1. 数据可视化:p5.js非常适合将枯燥的数据转化为直观的图表。你可以尝试用fetch()API 加载一个本地的JSON数据(比如一组城市人口数据),然后用矩形的高度或圆的面积来代表数据大小,制作成柱状图或气泡图。
  2. 生成艺术:利用随机数、噪声函数(noise())和算法,创作出不可预测的、独特的数字艺术作品。例如,用分形、L-system(树木生长模拟)或细胞自动机规则来生成复杂图案。
  3. 简单游戏开发:结合键盘、鼠标事件和碰撞检测,你可以制作简单的游戏,如打砖块、贪吃蛇、Flappy Bird等。这是理解游戏循环、状态管理和交互逻辑的好方法。
  4. 物理模拟:引入更真实的物理,比如重力加速度、弹性碰撞、摩擦力等,模拟小球落地、钟摆运动、软体晃动等效果。
  5. 与DOM元素结合:p5.js不仅可以绘制在画布上,还可以与网页上的HTML按钮、滑块、输入框等元素交互,创建更丰富的Web应用界面。

学习资源指引

  • 官方文档与示例:p5.js官网有最全面、最权威的参考文档和数百个在线示例,这是最好的学习资料库。
  • The Coding Train:Daniel Shiffman教授的YouTube频道和网站,他用极其热情和易懂的方式讲解p5.js和创意编程,其“代码编程”系列是经典入门教程。
  • OpenProcessing:一个在线的p5.js作品分享社区,你可以看到无数其他人的创意作品,并能够“查看源码”学习,是激发灵感的宝库。

6. 常见问题与调试技巧实录

在实际操作中,你一定会遇到代码不按预期运行的情况。别担心,这是学习的一部分。以下是我在教学中遇到的最常见问题及解决方法。

6.1 代码不运行或画布空白

这是新手最常遇到的问题,通常原因和解决步骤如下:

  1. 检查控制台:按F12打开浏览器的开发者工具,切换到“Console”(控制台)标签页。任何JavaScript错误(红色错误信息)都会在这里显示。最常见的错误是“Uncaught ReferenceError: ... is not defined”,这通常意味着你拼错了函数或变量名(比如把createCanvas拼成了creatCanvas)。仔细阅读错误信息,它会告诉你错误发生在第几行。
  2. 检查HTML引用:如果你使用本地文件方式,确保index.html中正确引入了p5.js库和你的sketch.js文件,并且文件路径正确。一个常见的错误是将sketch.js保存在了子文件夹里,但HTML中的引用路径没有相应调整。
  3. 检查函数名:确保你的核心函数名拼写完全正确:setupdraw,并且它们没有被包裹在另一个函数或条件语句里。它们应该是顶层的函数声明。
  4. 检查画布创建:确认createCanvas()函数被成功调用。有时在setup()里写了其他可能出错的代码,导致createCanvas()根本没执行。

6.2 图形位置或大小不对

这几乎总是坐标或参数理解有误。

  • “我的圆画到屏幕外面去了!”:回忆坐标系,原点在左上角。如果你用circle(0, 0, 100),这个圆的左半边和上半边就会在画布之外看不见。使用print(mouseX, mouseY);draw()里打印鼠标坐标,可以帮助你快速定位画布上的点。
  • “我想画在中心,但没居中”circle(width/2, height/2, diameter)才是将圆心置于画布中心。circle(width/2, height/2)只有两个参数,会被解释为circle(x, y),缺少直径参数,可能无法绘制或使用默认值。
  • 参数顺序混淆:不同的形状函数参数顺序不同。rect(x, y, width, height)是矩形,而ellipse(x, y, width, height)是椭圆。务必查阅文档。

6.3 动画卡顿或闪烁

  • 性能问题:如果在draw()中创建了大量对象(比如我们的粒子系统粒子数过多),或者执行了非常复杂的计算,会导致帧率下降。解决方法:优化算法,限制对象数量,对于不再需要的对象及时从数组中移除。
  • “闪烁”问题:这通常是因为没有在每一帧开始时用background()清除上一帧的画面,而你又绘制了半透明的图形,导致图像不断叠加变深。如果你想要保留上一帧的痕迹(如拖尾效果),就使用带透明度的background(),如background(0, 10)。如果你想要每一帧都是全新的,就使用不透明的background()。另一种“闪烁”可能源于绘制顺序,确保稳定的元素(如背景)最先绘制。

6.4 颜色不如预期

  • 灰度与RGB模式fill(150)是灰度值(0黑,255白)。fill(255, 0, 0)是RGB红色。fill(255, 0, 0, 150)是带透明度的红色。如果你传了三个参数,它会被认为是RGB;传了四个参数,则是RGBA。传一个参数,是灰度。
  • 颜色模式:p5.js默认是RGB模式,值范围0-255。你也可以使用colorMode(HSB)切换到色相、饱和度、亮度模式,有时这样调色更直观。切换后,参数范围也会变化(默认HSB范围是0-360, 0-100, 0-100)。如果不注意模式,颜色会非常奇怪。

6.5 调试心得:console.log()是你最好的朋友

当代码行为诡异时,不要光靠猜。在怀疑的变量变化处、函数调用处插入console.log()打印信息。

function draw() { let x = someComplexCalculation(); console.log('当前x的值是:', x); // 在控制台查看x是否计算正确 circle(x, 100, 50); }

通过查看控制台输出的值,你可以一步步追踪程序的实际执行流程,快速定位逻辑错误。这是所有程序员最常用、最有效的调试手段,没有之一。

从在画布上点亮第一个像素,到创造出跟随鼠标的精灵,再到模拟出拥有物理规律的粒子世界,p5.js用最直观的方式,将编程的抽象逻辑与人类的视觉创造力连接了起来。我见过许多自称“没有编程天赋”的学生,在让第一个图形动起来的瞬间,眼里迸发出的光芒。编程从来不是冰冷的符号游戏,它是一门关于创造、逻辑和表达的新语言。而p5.js,无疑是学习这门语言时,最有趣、最友好的一本“图画书”。别停留在模仿,试着改动参数,组合不同的函数,甚至把你手绘的草图用代码“翻译”出来。每一个错误提示,都是计算机在和你对话;每一行运行成功的代码,都是你在数字世界里留下的独一无二的印记。现在,画布已经为你铺好,画笔就在你的手中——开始创造吧。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 10:43:46

TTS-Backup完整指南:3步保护你的Tabletop Simulator游戏数据

TTS-Backup完整指南&#xff1a;3步保护你的Tabletop Simulator游戏数据 【免费下载链接】tts-backup Backup Tabletop Simulator saves and assets into comprehensive Zip files. 项目地址: https://gitcode.com/gh_mirrors/tt/tts-backup 还在为Tabletop Simulator&a…

作者头像 李华
网站建设 2026/7/28 10:42:56

3个高效方法:一站式获取Obsidian专业主题和CSS美化资源

3个高效方法&#xff1a;一站式获取Obsidian专业主题和CSS美化资源 【免费下载链接】awesome-obsidian &#x1f576;️ Awesome stuff for Obsidian 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-obsidian 想要让Obsidian知识管理工具拥有个性化界面和高效工作…

作者头像 李华
网站建设 2026/7/28 10:40:51

大模型终极思考:技术、人文与未来

大模型终极思考&#xff1a;技术、人文与未来 &#x1f4dd; 本章学习目标&#xff1a;通过本章学习&#xff0c;你将全面掌握"大模型终极思考&#xff1a;技术、人文与未来"这一核心主题&#xff0c;建立系统性认知。 一、引言&#xff1a;为什么这个话题如此重要 …

作者头像 李华
网站建设 2026/7/28 10:40:23

AI代码助手Token消耗异常排查:从DeepSeek接入到LiteLLM配置优化

最近在折腾 Codex 这类 AI 代码助手时,发现一个挺有意思的现象:很多开发者兴冲冲地把后端模型从 Claude 或 GPT 换成了 DeepSeek,本以为能省下一大笔 API 费用,结果跑起来一看,Token 消耗量不仅没降,反而像开了闸的水龙头一样,哗哗地流,账单数字跳得人心惊肉跳。这感觉…

作者头像 李华
网站建设 2026/7/28 10:39:52

TSDK源码解析:淘宝数据抓取核心组件实现原理

TSDK源码解析&#xff1a;淘宝数据抓取核心组件实现原理 【免费下载链接】TSDK 淘宝爬虫SDK&#xff0c;用于淘宝开放平台或淘宝、天猫、阿里巴巴登录爬取 项目地址: https://gitcode.com/gh_mirrors/ts/TSDK TSDK&#xff08;淘宝爬虫SDK&#xff09;是一款专注于淘宝开…

作者头像 李华
网站建设 2026/7/28 10:39:12

Docker实战 | Docker部署Haptic笔记管理工具完整指南

Docker实战 | Docker部署Haptic笔记管理工具完整指南一、Haptic介绍1.1 Haptic简介1.2 Haptic特点1.3 主要使用场景二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、下载Haptic镜像…

作者头像 李华