html5 canvas中实现重力感应碰撞需三层联动:用deviceorientation获取beta/gamma角映射为加速度,每帧按“加速度→速度→位置”更新状态并加阻尼,碰撞时先分离位置再按动量守恒更新速度。

要在HTML5 Canvas中实现基于重力感应的物理碰撞与动量反弹,关键在于三层联动:设备方向数据驱动加速度、每帧用物理公式更新运动状态、碰撞时按动量守恒简化处理速度分量。不是单纯“画球”,而是让球的每个位置和速度都由真实传感器输入和物理逻辑共同决定。
用DeviceOrientation获取倾斜角度模拟重力场
Canvas本身不感知重力,需靠设备传感器提供方向数据:
- 监听deviceorientation事件,从中提取beta(绕X轴俯仰角)和gamma(绕Y轴横滚角)
- 将角度映射为二维加速度分量:
ax = Math.sin(gamma * Math.PI / 180) * gScale
ay = Math.sin(beta * Math.PI / 180) * gScale
其中gScale是缩放系数(如0.2~0.5),避免抖动过大 - 注意:alpha(方向角)通常不用在重力模拟中,它反映的是设备朝向而非倾斜
每帧更新小球状态:加速度→速度→位置
所有小球共享同一套物理迭代流程,顺序不能错:
- 先叠加当前帧加速度:
ball.vx += ax;
ball.vy += ay; - 再更新位置:
ball.x += ball.vx;
ball.y += ball.vy; - 最后做阻尼衰减(模拟空气阻力):
ball.vx *= 0.995;
ball.vy *= 0.995;
边界与球间碰撞:分离优先,再更新速度
防止穿模和卡顿,必须先修正位置,再算反弹:
-
地面/墙面反弹:
检测ball.y + ball.r >= canvas.height时,设ball.y = canvas.height - ball.r,再执行ball.vy = -ball.vy * 0.85(恢复系数) -
两球碰撞检测:
计算中心距离平方:dx = b1.x - b2.x; dy = b1.y - b2.y;
若dx*dx + dy*dy ,则发生碰撞 -
碰撞响应(等质量简化版):
先沿连线方向分离两球,避免下一帧重复触发
再交换沿法线方向的速度分量:
v1n = (b1.vx * dx + b1.vy * dy) / dist;
v2n = (b2.vx * dx + b2.vy * dy) / dist;
交换后更新各自速度矢量
动画循环必须用requestAnimationFrame驱动
保证与屏幕刷新率同步,避免时间步长浮动导致物理失真:
- 整个循环结构固定为:
updatePhysics(); → checkCollisions(); → clearCanvas(); → renderBalls(); - 不使用setInterval——它无法适应不同设备帧率,会导致重力累积偏差
- 若需更高精度,可引入时间差deltaTime归一化加速度,但对轻量级重力感应应用非必需
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











