实现球体碰撞动画需手动编码动量守恒物理逻辑,用requestAnimationFrame驱动Canvas渲染;核心是坐标系旋转→法向一维碰撞(用质量加权速度公式)→坐标系还原,切向速度不变。

要实现基于动量守恒的球体碰撞动画,核心不是调用某个“Canvas动画接口”,而是用 JavaScript 手动计算物理逻辑,并用 Canvas 的 requestAnimationFrame 驱动渲染循环。Canvas 本身不提供物理引擎,它只负责绘图;动量守恒需由开发者根据经典力学公式推导并编码实现。
理解二维弹性碰撞中的动量与动能守恒
两个球发生理想弹性碰撞(无能量损耗)时,需同时满足:
- 总动量守恒:m₁v₁ + m₂v₂ = m₁v₁′ + m₂v₂′(矢量式)
- 总动能守恒:½m₁v₁² + ½m₂v₂² = ½m₁v₁′² + ½m₂v₂′²
实际编程中,不直接解联立方程,而是采用「坐标系旋转→一维碰撞→坐标系还原」策略:先将速度投影到连心线(碰撞法向)和切向,法向分量按一维弹性碰撞公式更新,切向分量保持不变。
关键公式(法向速度更新):
v₁n′ = v₁n × (m₁ − m₂) / (m₁ + m₂) + v₂n × 2m₂ / (m₁ + m₂)
v₂n′ = v₂n × (m₂ − m₁) / (m₁ + m₂) + v₁n × 2m₁ / (m₁ + m₂)
从零开始创建惊艳、动画丰富且自包含的 HTML 演示文稿,或通过转换 PowerPoint 文件生成。当用户希望制作幻灯片、构建演示文稿、打造路演资料(pitch deck)、将 PPT/PPTX 转换为网页格式,或增强现有 HTML 演示文稿时,应使用此能力。该能力帮助用户通过视觉预览而非抽象选项来发掘自身审美偏好。
在Canvas中实现碰撞检测与响应
步骤如下:
-
位置更新:每一帧用当前速度更新球心坐标(
x += vx; y += vy) - 边界检测:若球心距画布边缘距离 vx = -vx),并修正位置防止粘连
-
球-球碰撞检测:计算两球心距离 d;若
d ≤ r₁ + r₂,触发碰撞响应 -
碰撞处理:
- 计算单位法向量:
nx = (x₂ − x₁)/d,ny = (y₂ − y₁)/d - 分解速度:法向分量
v1n = v1x×nx + v1y×ny,切向分量v1t = v1x×(−ny) + v1y×nx(用垂直单位向量) - 套用上述法向速度更新公式,得到
v1n′和v2n′ - 合成新速度:
v1x′ = v1n′×nx − v1t×ny,v1y′ = v1n′×ny + v1t×nx(同理算 v2) - 为避免下一帧重复碰撞,沿法向将两球略微分离(如
x₁ -= nx×overlap×0.5)
- 计算单位法向量:
用 requestAnimationFrame 构建稳定动画循环
不要用 setInterval,使用浏览器原生的 requestAnimationFrame 更流畅且节电:
- 定义主循环函数,例如
function animate() { update(); render(); requestAnimationFrame(animate); } -
update()中更新所有球的位置、检测碰撞并修正速度/位置 -
render()中清空 canvas(ctx.clearRect(0,0,canvas.width,canvas.height)),再逐个绘制球(ctx.beginPath(); ctx.arc(x,y,r,0,Math.PI*2); ctx.fill();) - 可加入时间步长控制(如用
performance.now()计算 deltaT),使运动与帧率解耦,提升物理准确性
实用建议与常见陷阱
注意以下易错点:
- 未做碰撞后的位置分离 → 球会卡死或持续触发碰撞逻辑
- 法向/切向分解时混淆向量正交基 → 导致速度方向错误、能量不守恒
- 忽略质量影响 → 所有球设为等质量虽简化代码,但不符合动量守恒本质(质量大的球速度变化小)
- 浮点误差累积 → 长时间运行后球可能缓慢漂移,可在每次碰撞后对速度做微小阻尼(如 ×0.999)或定期归一化
- 多球密集场景下,一次循环内多个碰撞对可能相互影响 → 若精度要求高,需按碰撞时间排序或使用迭代求解(如 Verlet 积分)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










