p5.js 教程:对象与图片——用 loadImage()、preload() 和 ES6 类在画布中加载与显示图像

发布时间:2026/10/14 15:57:58
p5.js 教程:对象与图片——用 loadImage()、preload() 和 ES6 类在画布中加载与显示图像
教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载本篇技术指南围绕 The Coding Train「Code! Programming with p5.js」入门系列第 7.8 节《Objects and Images》展开讲解如何在 p5.js 中把图片作为对象的一部分来加载与绘制先通过preload()与loadImage()在程序启动前异步加载图片再将其封装进 ES6 类对象如Bubble配合数组批量生成多个带图像的交互对象并利用image()将图片缩放到指定尺寸绘制到画布上。读者学完后将掌握一套可复用的「图片 面向对象」p5.js 方案可直接应用于泡泡碰撞、卡片收集、贴图精灵等创意编程场景。一、本教程在系列中的定位本小节7.8-objects-and-images.md是「Code! Programming with p5.js」系列中对象交互Object Interaction部分的收尾章节发布于 2017-12-16对应视频i2C1hrJMwz0在线示例位于 p5.js Web EditorH44xHm5a。它的核心主题一句话即可概括探索如何使用 p5.js 加载图片并将图片作为对象的一部分显示出来。要理解本节需要先具备以下前置知识均为系列前序章节ES6 类与构造参数如何用class定义对象、用constructor(x, y, r)接收参数见 6.2-classes.md 与 6.3-constructor-arguments.md对象数组如何用循环和push()批量创建对象并存入数组见 7.3-array-of-objects.md鼠标交互如何让对象响应mousePressed()见 7.4-mouse-interaction.md对象间通信如何让对象彼此检测碰撞见 7.6-object-communication-1.md 与 7.7-object-communication-2.md。本节把上述「类 数组 鼠标交互」的能力再向前推进一步对象不仅绘制几何图形还可以持有并绘制图片。二、完整示例代码与运行方式仓库中本节的完整可运行示例位于 beginners/p5js/7.8-objects-and-images/目录结构如下beginners/p5js/7.8-objects-and-images/ ├── index.html # HTML 入口引入 p5.js 与 sketch.js ├── sketch.js # 主程序加载图片、定义 Bubble 类、实现交互 └── kittens/ # 图片素材目录 ├── flower.png # 一朵花100×100 ├── kitten0.jpg # 小猫图片 0100×96 ├── kitten1.jpg # 小猫图片 1100×90 ├── kitten2.jpg # 小猫图片 2100×98 ├── kitten3.jpg # 小猫图片 3100×102 └── kitten4.jpg # 小猫图片 4100×972.1 HTML 入口文件index.html 的结构非常精简仅引入 p5.js 库与主脚本!DOCTYPE html html head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1 titleKittens/title script typetext/javascript srchttps://cdn.jsdelivr.net/npm/p51.4.1/lib/p5.min.js/script script typetext/javascript srcsketch.js/script /head body /body /html需要说明的是示例通过 CDN 引入了p51.4.1版本如果你在本地使用其他版本的 p5.jsloadImage()、image()、preload()等 API 的基本用法保持一致。2.2 主程序 sketch.jssketch.js 是本节的核心完整代码如下为便于讲解加了行号内容与仓库一致// Objects and Images // Code! Programming with p5.js // The Coding Train / Daniel Shiffman // https://thecodingtrain.com/beginners/p5js/7.8-objects-and-images.html // https://youtu.be/i2C1hrJMwz0 // https://editor.p5js.org/codingtrain/sketches/H44xHm5a let bubbles []; let flower; let kittens []; function preload() { flower loadImage(kittens/flower.png); for (let i 0; i 5; i) { kittens[i] loadImage(kittens/kitten${i}.jpg); } } function setup() { createCanvas(600, 400); for (let i 0; i 10; i) { let x random(width); let y random(height); let r random(50, 150); // let kitten random(kittens); let b new Bubble(x, y, r); bubbles.push(b); } } function mousePressed() { for (let i 0; i bubbles.length; i) { bubbles[i].clicked(mouseX, mouseY); } } function draw() { background(0); for (let i 0; i bubbles.length; i) { bubbles[i].move(); bubbles[i].show(); } } class Bubble { constructor(x, y, r, img) { this.x x; this.y y; this.r r; this.kitten random(kittens); } clicked(px, py) { //let d dist(px, py, this.x, this.y); //if (d this.r) { if ( px this.x px this.x this.r py this.y py this.y this.r ) { this.kitten flower; //random(kittens); } } move() { this.x this.x random(-2, 2); this.y this.y random(-2, 2); } show() { image(this.kitten, this.x, this.y, this.r, this.r); // stroke(255); // strokeWeight(4); // fill(this.brightness, 125); // ellipse(this.x, this.y, this.r * 2); } }2.3 运行方式p5.js Web Editor打开在线示例H44xHm5a即可直接运行这是最省事的途径本地运行将index.html、sketch.js与kittens/目录放在同一文件夹下通过本地 HTTP 服务访问。注意由于浏览器安全策略直接双击打开 HTML 文件file://协议时loadImage()很可能无法读取本地图片建议使用本地服务器例如在项目目录下执行python -m http.server详见 9.12-local-server-text-editor-javascript-console.md 中对本地服务器的讲解。三、关键 API 详解preload()、loadImage() 与 image()3.1 preload()确保图片在 setup() 前加载完成p5.js 中存在一个特殊生命周期函数preload()它会在setup()之前被调用。所有耗时的异步加载操作如loadImage()、loadJSON()、loadSound()等都应该放在preload()中这样程序会等待加载完成后再执行setup()从而保证setup()与draw()使用图片时数据一定就绪。本示例的加载逻辑如下function preload() { flower loadImage(kittens/flower.png); for (let i 0; i 5; i) { kittens[i] loadImage(kittens/kitten${i}.jpg); } }这里演示了两种图片管理策略单个图片变量flower直接保存单张flower.png图片数组kittens用循环批量加载kitten0.jpg到kitten4.jpg注意这里使用了 ES6 模板字符串kittens/kitten${i}.jpg动态拼接文件名。两个全局变量flower与kittens声明在preload()之外模块顶层以保证在preload()、setup()、draw()以及类方法中都能访问。3.2 loadImage()从文件路径加载图片loadImage()接受图片的相对路径也可传 URL返回一个p5.Image对象。加载完成后这个对象内部持有图片的像素数据与尺寸信息后续可以被反复绘制、缩放甚至通过pixels[]逐像素读写后者属于更进阶的图像处理话题本示例未涉及。路径解析原则相对路径是相对于 HTML 文件所在位置解析的。因此kittens/flower.png会解析为index.html同级的kittens/目录下的flower.png与仓库中的目录结构完全对应。3.3 image()在画布上绘制图片show()方法中的一行image()调用完成了图片绘制image(this.kitten, this.x, this.y, this.r, this.r);其常用签名与参数含义如下参数含义img第 1 参要绘制的p5.Image对象x,y图片左上角在画布上的坐标w,h可选绘制宽度与高度不传则按图片原始尺寸绘制在示例中w和h都取对象的this.r半径于是图片被缩放为边长r的正方形。这正好呼应了setup()中r random(50, 150)的设置——每个泡泡的图片大小各不相同形成错落有致的视觉效果。注释中还保留了原来的圆形绘制代码ellipse(this.x, this.y, this.r * 2)说明从「几何图形」过渡到「图片」时只需把绘制命令从ellipse()换成image()即可对象的结构无需改变。四、面向对象设计把图片装进 Bubble 类4.1 构造函数每个对象随机获得一张图片class Bubble { constructor(x, y, r, img) { this.x x; this.y y; this.r r; this.kitten random(kittens); } ... }构造函数接收位置与尺寸参数(x, y, r)并在内部执行this.kitten random(kittens)从kittens数组中随机抽取一张小猫图片作为该对象的「外观」。注意第 4 个参数img虽然在构造签名中声明但本示例并未使用它传值——图片是在构造函数体内通过random(kittens)直接指定的。这是一个可以自行改写的点如果想让外部决定每张图片也可以把img参数真正用起来例如new Bubble(x, y, r, kittens[i])。4.2 行为方法move()、show() 与 clicked()Bubble类包含三个方法对应「移动、绘制、交互」三个职责move()让对象在画布上做随机游走。每帧给x、y加上random(-2, 2)的偏移实现轻微的抖动漂浮效果show()调用image(this.kitten, this.x, this.y, this.r, this.r)绘制当前持有的图片clicked(px, py)接收鼠标坐标判断鼠标是否落在对象的矩形范围内即px在x与x r之间、py在y与y r之间若命中则把该对象的图片替换为flower。clicked(px, py) { if ( px this.x px this.x this.r py this.y py this.y this.r ) { this.kitten flower; //random(kittens); } }这是本节最有意思的交互逻辑点击任意小猫泡泡它会「变成」一朵花。注释掉的代码let d dist(...); if (d this.r)提示了另一种思路——用圆心距离判断圆形命中区域矩形判断是它的简化替代。两种方式都能实现点击检测圆形判定更符合「泡泡」的直觉矩形判定则更简单直接。4.3 setup()用循环与 push() 批量生成对象function setup() { createCanvas(600, 400); for (let i 0; i 10; i) { let x random(width); let y random(height); let r random(50, 150); let b new Bubble(x, y, r); bubbles.push(b); } }程序启动时创建 10 个随机位置、随机大小的Bubble对象并存入bubbles数组——这正是 7.3-array-of-objects.md 中「对象数组 push()」模式在本节的直接复用。draw()中再用循环依次调用每个对象的move()与show()。4.4 mousePressed()把鼠标事件分发到所有对象function mousePressed() { for (let i 0; i bubbles.length; i) { bubbles[i].clicked(mouseX, mouseY); } }p5.js 的内置事件函数mousePressed()在鼠标按下时触发这里遍历所有泡泡把mouseX、mouseY传给每个对象的clicked()方法由对象自己判断是否被点到。这是 7.4-mouse-interaction.md 中「对象与鼠标交互」模式的延续。五、从源码看本节的技术脉络结合 sketch.js 的源码可以清晰地看到本节串联起来的完整技术链条异步加载preload()loadImage()保证图片资源就绪比「直接在setup()里加载」更稳妥数据结构顶层let kittens []用数组管理多张图片bubbles数组管理多个对象面向对象封装图片作为对象属性this.kitten随对象一起移动、绘制与替换事件分发全局mousePressed()遍历对象数组把交互逻辑下放到对象方法绘制替换image()把p5.Image按指定尺寸绘制实现图片的缩放显示与状态切换小猫 → 花。从示例的注释如//let kitten random(kittens);、//random(kittens);可以看出作者在录制视频时经历了「逐个指定图片 → 随机分配图片 → 点击替换图片」的演进过程这些注释本身就是理解思路的线索最初可能想在setup()里直接给每个泡泡分配图片最终选择在Bubble构造函数里随机抽取点击时再统一替换为flower。六、延伸与变体建议本节示范的「对象携带图片」模式非常通用可以在此基础上做多种扩展点击随机换图把clicked()中this.kitten flower改回random(kittens)实现「点击一次换一张小猫」的效果圆形命中检测用dist(px, py, this.x, this.y) this.r替代矩形判断让点击区域更符合圆形泡泡的直觉对象间图片交换结合 7.7-object-communication-2.md 的双重循环碰撞检测让两个泡泡相撞时交换各自的图片动态生成素材不使用外部图片而是结合 9.23-create-graphics.md 的createGraphics()在运行时动态生成贴图再赋给对象更丰富的加载方式参考 8.15_p5.js_drag_and_drop 中loadImage与拖放事件的结合实现用户拖入图片后立即作为对象外观渲染。如果希望在团队或社区中分享自己的变体作品可以参考 community-contribution-guide.md 中关于贡献示例的说明。七、小结《Objects and Images》虽然是一节不到 80 行的入门示例却完整演示了 p5.js 创意编程中「加载图片 → 管理图片 → 用图片绘制对象 → 交互替换图片」的完整闭环preload()与loadImage()负责可靠地加载资源数组负责管理多张图片与多个对象ES6 类把「图片」作为对象属性封装使每个泡泡拥有独立的外观与行为image()一行代码完成缩放绘制mousePressed()与对象方法clicked()完成点击交互。这套模式是从「画几何图形」进阶到「绘制真实素材」的关键一步也是后续大量 p5.js 项目精灵动画、贴图粒子、交互式拼贴等的共同基础。对照仓库中的完整代码 sketch.js 亲手运行一遍再尝试上述变体即可把本节知识转化为自己的创作能力。赞分享教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载相关推荐Avalonia图像处理图片加载与显示Avalonia图像处理图片加载与显示 概述 在现代跨平台应用开发中图像处理是不可或缺的核心功能。Avalonia作为.NET生态系统的跨平台UI框架提供跨平台桌面应用UI组件ml5.js 图像分类实战用 MobileNet 预训练模型在 p5.js 中识别图片内容ml5.js 图像分类实战用 MobileNet 预训练模型在 p5.js 中识别图片内容 本文围绕 Coding Train 的 ml5.js 初学者指南系教程文档示例工程p5.js 入门教程 7.3用 ES6 Class 与数组创建对象数组Array of Objectsp5.js 入门教程 7.3用 ES6 Class 与数组创建对象数组Array of Objects 导读 本节教程来自《Code! Programm教程文档示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考