关于本文
本文是通过利用生成式 AI 的自动化生成流程创建的。
我们在查阅了 MDN 的 Canvas 动画、requestAnimationFrame 以及减少动态效果的第一手资料后,制作了这款可改变重力和反弹系数的 JavaScript 教学课件。验证状态:📘 已确认官方信息、V8 语法和数值计算 / 浏览器实机未验证
2026年10月31日,我们将 Daily Code 的三个文件保存并读取回 GitHub,检查了下落、碰撞、反弹以及在地面静止的条件。GitHub Pages 的访问、WordPress 的蓝色边框、以及移动端和打印/PDF 的实际显示效果尚未验证。
通过让小球落下并弹起,你可以亲眼看到在 JavaScript 中处理速度、位置和加速度的意义。这是一个能够逐一对比改变重力与改变反弹系数时差异的教学课件。
本次可以实现的功能
| 项目 | 条件 |
|---|---|
| 支持情况 | 支持 Canvas 2D 和 JavaScript 的浏览器(实机未验证) |
| 技术 | Canvas API / requestAnimationFrame |
| 费用 | 无需外部库、付费 API 或登录 |
| 通信 | 仅加载页面。不向外部发送操作结果 |
| 操作 | 播放・停止・前进0.2秒・重置・滑块 |
| 数据 | 虚拟球。不含个人信息或位置信息 |
先试一试:让球弹跳起来
🔷 只需3项操作即可体验
🏀 打开 Canvas 弹跳演示(公开・浏览器运行状态未确认)
📘 完成版 HTML・JavaScript・README
- 点击“播放”,观察球下落和弹跳的过程。
- 将“恢复系数”从 0.80 改为 0.45。
- 点击“重置”,然后从相同高度再次开始运动。
🟦 操作后请看这里
请同时确认绘图区域下方的“距地面高度 (px)”和“碰撞次数”。如果觉得运动难以看清,可以使用“前进0.2秒”作为静态画面追踪变化。
| 条件 | 预期变化 |
|---|---|
| 反弹系数 0.80 | 弹跳较高 |
| 反弹系数 0.45 | 弹跳较低 |
| 重力 600 → 1000 px/s² | 更快到达地面 |
| 暂停 | 保留位置和次数 |
| 前进 0.2 秒 | 推进计算并显示静止状态 |
这些是根据代码预测的期望结果,并非实际浏览器的测量结果。 每次比较时,请点击“重置”以统一初始条件。
为什么球会弹跳
Canvas 是绘制圆形和线条的区域。JavaScript 会更新球的当前位置并重复重新绘制,从而呈现出运动效果。本教程中使用的是屏幕像素制作的简化物理模型。
若将垂直方向的速度设为 vy、位置设为 y、加速度设为 g、经过时间设为 dt,则处理的核心如下:
vy = vy + g * dt; // 速度を更新する
y = y + vy * dt; // 位置を更新する
if (y >= floor - radius) {
y = floor - radius; // 床の位置に戻す
vy = -vy * restitution; // 反対方向へ跳ねる
}
此代码仅为展示思路的片段,并非可独立运行的完整版本。Daily Code 的 JavaScript 主体包含在球静止于地面后不再增加碰撞次数的处理、停止计时器以及对减少动画运动设置的支持等。
flowchart LR
A["再生・コマ送り"] --> B["速度・位置の更新"]
B --> C{"床に接した?"}
C -->|はい| D["反発係数で速度を反転"]
C -->|いいえ| E["その位置を使用"]
D --> F["Canvasに再描画"]
E --> F
F --> G["高さ・衝突回数を更新"]
浏览器的 requestAnimationFrame 是一种请求在下一次重新绘制前调用处理程序的 API。为了防止其在高刷新率屏幕上显得异常迅捷,它会使用自上一次以来的经过时间。如果屏幕被隐藏,则会停止播放,同时抑制因经过时间过长而导致的突然位移。
修改一处进行对比
将恢复系数固定为0.80,仅将重力设置从600 px/s²更改为1000 px/s²。每次都点击“重置”以统一初始条件。
| 比较 | 重力 | 预期结果 |
|---|---|---|
| 更改前 | 600 px/s² | 基准下落速度 |
| 更改后 | 1000 px/s² | 更快到达地面 |
这里改变的只有重力。如果同时改变恢复系数,将难以判断是哪个因素造成了差异。
px/s²是使用画布像素坐标的教学单位。它并不直接表示地球的重力加速度。不能用于实际材料或机械的安全计算。
尊重减少动画的设置
⚠️ 不适应连续动画时
当操作系统或浏览器的减少动态效果设置(prefers-reduced-motion: reduce)有效时,连续播放将被禁用。你可以通过“前进0.2秒”逐帧观察静态图像。打开页面时不会自动播放。
普通模式也可以通过“停止”按钮中断,切换到其他标签页时会停止播放。在智能手机上,内部画布坐标 720×360 会通过 CSS 进行缩放,因此屏幕下方的像素值与屏幕的物理像素数不一致。
在自己的电脑上运行
HTML与JavaScript保存在同一个文件夹中,并在浏览器中打开HTML。如果需要,可以通过以下命令启动本地服务器并访问 localhost。
python3 -m http.server 8000 --bind 127.0.0.1
要打开的URL是 http://127.0.0.1:8000/ 。如果Windows上可以使用Python Launcher,也可以通过 py -3 -m http.server 8000 –bind 127.0.0.1 来运行。按 Ctrl+C 退出。
如果运行不正常
| 症状 | 确认 |
|---|---|
| 一直处于加载状态 | app.js的位置及控制台(Console)错误 |
| 小球不移动 | 播放操作、减少动画设置 |
| 碰撞次数没有增加 | 是否推进到了小球触底 |
| 比较结果不稳定 | 是否重置并匹配了初始条件 |
| 看起来很小 | Canvas内部坐标与CSS显示宽度的差异 |
如何在工作和学习中使用?
它可以应用作游戏、学习教材以及展示状态变化的UI基础。但是,反弹效果看起来正确并不意味着验证了现实中的物理现象。实际业务中的计算需要与实测值进行核对、单位换算、边界条件以及误差评估。
比较接触地面瞬间的位置与速度
在球触地瞬间,不仅需要弹回的速度,还需要将其处理回不会超出地面的位置。由于向屏幕下方移动的球是一个圆,如果将其中心坐标设为与地面高度相同,则下半部分会陷入地面。中心位置必须放在地面高度减去半径的位置。如果只修正位置而保持向下的速度不变,它将在下一次更新时再次试图进入地面。相反,如果不反转速度并修正位置,它可能会表现得像从地面下方弹回一样。这就是文章中的代码片段要进行这两种处理的原因。
恢复系数是教学用的一个数值,表示碰撞前瞬间的速度在碰撞后保留了多少。0.80意味着保留了比较大的速度,而0.45则较小。不能因为恢复系数减半,弹起的高度就简单地减半。高度还受到速度、加速度和经过时间的影响。请观察从相同高度落下、固定重力、仅改变系数时的区别。如果在比较之前没有重置,残留的上一次速度可能会导致结果无法解读。
可以预料,增大重力会缩短到达地面的时间。但是,如果同时改变恢复系数,就会分不清到底是哪个设置导致了弹跳方式的区别。在文章的对照表中,当把重力从600改到1000时,恢复系数固定为0.80。此时,请关注下落过程中速度的增长方式,不要把碰撞次数作为唯一的成功条件。在接下来的实验中,将重力改回600,只把恢复系数降低到0.45。如果将这两个实验分开,将更容易理解加速度的变化与碰撞时的能量损失之间的差异。
观察时间的推进方式
屏幕上的运动看起来是连续的,但程序是以极短的时间间隔更新速度和位置的。如果不考虑表示经过时间的dt,外观速度可能会因设备渲染次数的不同而有所变化。如果在切换标签页经过较长时间后返回,球在返回的瞬间突然表现得像是穿透了地面,这可能是由于将较长的时间合并计算所致。本教材采用了抑制这种影响的思路,但并非在所有环境下都实际测量出了相同的结果。
在推进0.2秒的操作中,并非观察连续的画面,而是可以作为静态图像来观察推进了短时间后的结果。如果尚未触地,碰撞次数没有增加是正常的。如果在接触地面后碰撞次数持续增加,则需要确认是否将静止状态每次都算作了一次新的碰撞。不仅要看数值,还要将其与距离地面的高度同时观察,这样更容易理解状态。给静止的球强行赋予速度,与作为计算结果而停止,这两者也是不同的。
本教材中的px/s²是在Canvas内部坐标中设置的加速度。它并非现实中的重力或机械材料特性的测量值。虽然它可以应用于游戏或学习教材的UI,但不能用于计算来评估现实装置的安全性。对于不擅长观察动态的用户,可以通过逐帧播放和状态显示来在相同条件下进行观察。在应用于实际业务时,不要将重要信息仅仅局限于屏幕的颜色和动态,这也是一个重要的观点。
官方信息与参考资料
官方资料确认日期:2026年10月31日。虽然执行了GitHub源代码读取、V8语法和计算检查,但尚未确认Pages发布、实际浏览器运行情况以及WordPress的蓝色边框显示。
