- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
本篇技术指南以 Coding Train《The Nature of Code》第 3.4 节「Polar Coordinates」为核心,系统讲解三角函数(正弦、余弦、正切)与极坐标思维在 p5.js 中的落地用法。你将学会用cos()/sin()把"角度 + 半径"翻译成画布上的x / y坐标,并基于仓库中 basic-polar-coordinates、spiral、random-trail、circular-shape 四个可运行示例,亲手实现圆周运动、螺旋线、随机轨迹与不规则环形图案——这些正是后续振荡运动、粒子系统与自主代理(wander)编程的数学基础。
为什么要"用极坐标思考"?
在 p5.js 里,绘制任何点都默认使用直角坐标系(笛卡尔坐标):一个点的位置由(x, y)描述。但自然界里大量运动天然围绕"中心 + 角度"展开——钟摆的摆动、行星的公转、雪花的分支、鱼的转向,本质上都是极坐标(Polar Coordinates)问题:用半径 r(到原点的距离)和角度 θ来定位一个点。
极坐标到直角坐标的换算,正是本节的灵魂公式:
x = r * cos(θ) y = r * sin(θ)当角度 θ 从 0 递增到 2π(即TWO_PI)时,点(x, y)就会在半径为 r 的圆上完整地绕一圈。理解了这一点,你就能用"半径 + 角度"两个标量轻松描述任何旋转、盘旋与环形图案,而不是手动推算一长串直角坐标。
三角函数三兄弟:sin、cos、tan
在进入代码之前,先厘清三个核心三角函数的几何含义(本视频 0:11–5:49 部分重点讲解):
| 函数 | 含义 | 值域(弧度制) | 在 p5.js 中的典型用途 |
|---|---|---|---|
sin(θ) | 角度 θ 对应单位圆上的y 分量 | [-1, 1] | 由角度求纵向偏移、垂直方向的速度分量 |
cos(θ) | 角度 θ 对应单位圆上的x 分量 | [-1, 1] | 由角度求横向偏移、水平方向的速度分量 |
tan(θ) | 对边 / 邻边 =sin(θ) / cos(θ) | 无界 | 由向量求指向角(见 3.3 的heading()) |
三个函数接受的都是弧度(radians)而非角度(degrees)。p5.js 中一个整圆为TWO_PI(约 6.283),半个圆为PI,四分之一圆为PI / 2。如果想用度数,可用angleMode(DEGREES)切换(详见 3.1 角度与旋转 一节)。
从源码结构看,本系列的教学编排也是层层递进的:3.2 节把"矢量运动"的思想迁移到角度上(角速度、角加速度),3.3 节再用p5.Vector.fromAngle()与vel.heading()建立"向量 ↔ 角度"的双向转换,而 3.4 节正是把三角函数与极坐标作为核心工具正式展开。
示例一:基础极坐标——让一个点沿圆周运动
仓库中的第一个示例 basic-polar-coordinates/sketch.js 是最直白的演示:用一个黄色圆点沿半径为 150 的圆周匀速移动。
let angle = 0; function setup() { createCanvas(400, 400); } function draw() { background(0); stroke(255); strokeWeight(4); noFill(); translate(200, 200); // 把坐标系原点移到画布中心 let r = 150; // 固定半径 circle(0, 0, r * 2); // 画出参考圆 strokeWeight(32); stroke(252, 238, 33); // 编码列车标志性的黄色 let x = r * cos(angle); let y = r * sin(angle); point(x, y); // 在极坐标换算出的位置画点 angle += 0.01; // 每帧旋转一点点 }关键点逐行拆解:
translate(200, 200):把原点从画布左上角移到中心。此后所有坐标都相对新原点计算,极坐标的"半径"才有了直观意义。let r = 150:固定半径,点的运动轨迹被约束在圆上。let x = r * cos(angle); let y = r * sin(angle);:核心换算公式,把极坐标(r, angle)转成画布坐标(x, y)。angle += 0.01:每帧增加 0.01 弧度。约TWO_PI / 0.01 ≈ 628帧走完一整圈(约 10.5 秒)。数值越大,转得越快——这就是"角速度"的雏形,与 3.2 角运动 的思路一脉相承。
运行效果:画布中央出现一个白色参考圆,黄色大圆点沿圆周匀速绕行。
示例二:螺旋——让半径随时间收缩
把"固定半径"改为"每帧递减",圆就变成了向内收拢的螺旋线。spiral/sketch.js 中注释掉了参考圆与背景重绘,让每一帧的点迹层层叠叠地留在画布上:
let angle = 0; let r = 150; function setup() { createCanvas(400, 400); background(0); // 只清屏一次,后续不重绘背景 } function draw() { translate(200, 200); strokeWeight(16); stroke(252, 238, 33); let x = r * cos(angle); let y = r * sin(angle); point(x, y); angle += 0.04; // 每帧旋转 0.04 弧度 r -= 0.2; // 半径每帧缩小 0.2 }两个增量参数直接决定螺旋形态:
| 参数 | 作用 | 本例取值 | 调整效果 |
|---|---|---|---|
angle += 0.04 | 每帧转过的弧度 | 0.04 | 越大圈越密、转速越快 |
r -= 0.2 | 每帧半径收缩量 | 0.2 | 越大螺旋收拢得越快;半径减到 0 以下后点会越过中心继续"穿出" |
因为background(0)只执行了一次,黄点走过的每一帧位置都被保留,形成从圆周向中心收拢的明亮螺旋线。
示例三:随机轨迹——给运动加入随机性
random-trail/sketch.js 在前一个示例的基础上引入随机量,并改用半透明背景制造"轨迹渐隐"效果:
let angle = 0; let r = 150; function setup() { createCanvas(400, 400); } function draw() { background(0, 10); // 半透明黑色,旧点逐渐淡出 translate(200, 200); strokeWeight(16); stroke(252, 238, 33); let x = r * cos(angle); let y = r * sin(angle); point(x, y); angle += 0.05; // 固定角增量 // angle += random(-0.1, 0.1); // 可取消注释:角度也随机抖动 r -= random(-2, 2); // 半径在每帧 -2 ~ +2 之间随机变化 }与螺旋示例的核心差异:
background(0, 10):第二参数是 alpha 透明度。每帧用 10/255 透明度的黑色覆盖画布,旧点不会立即消失而是逐步淡出,形成流动的拖尾轨迹。r -= random(-2, 2):半径不再单调收缩,而是每帧在 -2 到 +2 之间随机增减,轨迹在"扩张—收缩"之间游走。- 源码中还保留了一行被注释的
angle += random(-0.1, 0.1),取消注释即可让角度也带上随机抖动——这是探索"确定性运动 + 随机扰动"两种风格的最佳实验入口。
示例四:自定义环形形状——用 beginShape 画出不规则圆环
最后一个示例 circular-shape/sketch.js 展示了极坐标的进阶用法:不再逐帧画点,而是一次性沿圆周采样大量顶点,并用随机半径勾勒出有机的环形轮廓。
let angle = 0; let r = 150; function setup() { createCanvas(400, 400); } function draw() { background(0); translate(200, 200); stroke(255); strokeWeight(4); noFill(); // let increment = map(mouseX, 0, width, PI, 0.01); // 交互版:鼠标控制顶点密度 let increment = 0.1; // 每 0.1 弧度采样一个顶点 noLoop(); // 只绘制一帧,得到静态图形 beginShape(); for (let a = 0; a < TWO_PI; a += increment) { let r1 = r + random(-50, 10); // 每个顶点的半径随机偏移 let x = r1 * cos(a); let y = r1 * sin(a); vertex(x, y); } endShape(CLOSE); }实现要点:
for (let a = 0; a < TWO_PI; a += increment):角度从 0 遍历到 2π,步长increment = 0.1,共约 63 个采样点。步长越小顶点越多、轮廓越圆润;步长越大越呈多边棱角。let r1 = r + random(-50, 10):每个顶点独立获得半径扰动(-50 到 +10),这是图形呈现"不规则感"的关键,也解释了为何形状偏向一侧隆起——扰动区间不对称(偏负更多)。beginShape() ... vertex(x, y) ... endShape(CLOSE):p5.js 的形状构建 API,把所有极坐标采样点依次连线并闭合,生成完整的封闭轮廓。noLoop():停用持续刷新,只渲染一帧静态图形。每次刷新页面都会得到一幅不同的随机环形图案。- 源码注释提供了交互升级方案:用
map(mouseX, 0, width, PI, 0.01)把鼠标横坐标映射为采样步长,即可实时改变轮廓的细腻程度。
运行效果:画布中央出现一个白色不规则环形轮廓,像一块随机起伏的"石头"或"斑块",每一次刷新形状都独一无二。
纵深补充:向量与角度的双向转换(3.3 节的工具)
极坐标不只服务于"画圆"。在 3.3 角度与向量 中,p5.js 提供了两个与本节公式互为逆运算的工具,配合极坐标能解决"物体朝向运动方向"这类高频问题:
p5.Vector.fromAngle(angle):由角度直接生成单位向量(cos(angle), sin(angle)),等价于本节的x = r * cos(angle)一行写法。见 3.3 的 vehicle 示例:this.vel = p5.Vector.fromAngle(this.angle)。vec.heading():返回向量指向的角度(内部基于atan2),等价于从直角坐标反解出角度。见 direction-pointing 示例:this.angle = this.vel.heading()后再rotate(this.angle)让三角形对准运动方向。
这套"角度 ↔ 向量"工具与本节公式共同构成了振荡与转向类模拟的完整工具箱,后续 5.5 漫游行为 中会再次引用极坐标来生成随机转向角度。
实战延伸:极坐标 × 柏林噪声——不规则闭合曲线
极坐标最优雅的应用之一,是用它"驱动"柏林噪声采样,生成永远闭合、永不平滑的有机曲线。仓库中的 Polar Perlin Noise Loops(Coding Challenge #136) 正是这一思路的完整实现,其 P5/sketch.js 核心逻辑如下:
let xoff = map(cos(a + phase), -1, 1, 0, noiseMax); let yoff = map(sin(a + phase), -1, 1, 0, noiseMax); let r = map(noise(xoff, yoff, zoff), 0, 1, 100, height / 2); let x = r * cos(a); let y = r * sin(a);其中a同样从 0 遍历到TWO_PI,但半径r不再固定或随机,而是由二维柏林噪声noise(xoff, yoff)决定——而xoff、yoff恰好由cos(a)、sin(a)映射而来,形成"圆环路径上采样噪声"的巧妙结构。这正是 3.4 节"以角度为驱动、以半径为输出"思想的直接延伸:只要半径是平滑函数,闭合曲线就能呈现自然的形变。
延伸学习路径
本节处于《The Nature of Code》第三章"振荡运动"的中段,与相邻章节构成完整知识链:
- 前置:3.1 角度与旋转(弧度制与
angleMode)、3.2 角运动(角速度/角加速度)、3.3 角度与向量(fromAngle与heading)。 - 后置:3.5 简谐运动(用
sin()生成波动)、3.6 绘制正弦曲线 与 3.7 叠加波,最终过渡到第 5 章自主代理。 - 应用:Asteroids 小游戏(Coding Challenge #46) 用角度控制飞船朝向;Polar Perlin Noise Loops(#136) 用极坐标绘制噪声闭合曲线;第 5.5 节 wander 漫游 直接复用本节思想生成转向角度。
动手练习建议
- 修改示例一的
angle += 0.01为angle += 0.05,观察转速变化,并把半径换成r = 50 * sin(angle) + 100,看看轨迹如何从圆变成花瓣状。 - 在示例三中取消
angle += random(-0.1, 0.1)的注释,对比"平滑螺旋"与"抖动轨迹"两种运动质感。 - 为示例四加入颜色:用
stroke随a变化的hue值,做出彩虹环形图案(仓库社区贡献中即有 "Rainbow Spiral using Polar Coordinates" 的同类作品)。
四个示例的完整代码均可在仓库目录 learning/nature-of-code/3.4-polar-coordinates/ 下查看与运行,每个子目录都包含标准index.html(通过 CDN 引入 p5.js 1.4.1)与独立的sketch.js,下载后直接在浏览器打开即可体验。
- 教程
- 文档
- 示例工程
【免费下载链接】website-archive
Archive of the Coding Train website (first version)
相关推荐
用 CSS 绘制常见几何形状:方块、圆形与三角形实战指南(30-seconds-of-code)
用 CSS 绘制常见几何形状:方块、圆形与三角形实战指南(30 seconds of code) CSS 不仅能用来布局和美化页面,还能仅凭 width 、 h
教程文档p5.js 自定义形状绘制指南:beginShape、vertex 与 curveVertex 的完整实战
p5.js 自定义形状绘制指南:beginShape、vertex 与 curveVertex 的完整实战 在 p5.js 中,默认的绘图原语( rect 、
教程文档示例工程Circle Morphing(一):用极坐标与线性插值实现圆到三角形的形状变形
Circle Morphing(一):用极坐标与线性插值实现圆到三角形的形状变形 本篇技术指南围绕 Coding Train「编码挑战」系列第 81.1 期展开
教程文档示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考