用requestAnimationFrame驱动物理引擎需严格绑定计算与绘制:先update(重力→位置→碰撞检测→位置修正→速度更新)再render(清空画布→绘制),防穿模、拖影、重复碰撞。

用 requestAnimationFrame 驱动物理引擎做碰撞反弹,核心是把“计算”和“绘制”严格绑定在每一帧里,确保位置、速度、碰撞响应都同步更新,不跳帧、不累积误差。
动画循环必须用 requestAnimationFrame
不用 setInterval 或 setTimeout,因为它们不跟屏幕刷新率同步,容易掉帧或卡顿。正确写法是:
- 定义一个
animate()函数,内部先调用update()(算物理),再调用render()(画画面) - 末尾加
requestAnimationFrame(animate)形成递归循环 - 浏览器会自动按当前设备刷新率(如 60Hz)调度,省电又顺滑
物理更新要按顺序执行
每帧内 update 必须严格遵循这个顺序,否则会出现穿模、粘连或反弹方向错乱:
- 先更新所有小球的速度:比如加一次重力
vy += g - 再更新所有小球的位置:比如
x += vx; y += vy - 接着做碰撞检测:先边界(地面/左右墙),再球与球之间
- 检测到碰撞后立刻修正位置(如把球托回 canvas 底部)并更新速度(如
vy = -vy * damping)
碰撞响应要防重复触发
两球刚碰上那一帧,如果只改速度不调位置,下一帧可能还在“重叠”状态,导致连续多帧误判为持续碰撞。解决办法是:
- 算出重叠量(比如
d = r1 + r2 - distance) - 沿两球中心连线方向,把它们各推开一半重叠距离
- 再按动量守恒公式更新法向速度分量,切向速度保持不变
Canvas 绘制要清空再重绘
每次 render 前必须清空画布,否则运动轨迹会拖影:
- 简单背景用
ctx.clearRect(0, 0, canvas.width, canvas.height) - 如果背景复杂或有静态元素,可考虑双缓冲(两个 canvas 交替使用)
- 绘制小球统一用
ctx.arc(x, y, r, 0, Math.PI * 2),别漏掉ctx.fill()
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











