常见的2D碰撞检测
在2D游戏开发、图形界面交互及物理模拟中,2D碰撞检测是核心功能之一。它决定了物体是否发生接触、碰撞后的响应方式,直接影响用户体验的真实性与流畅性。本文将从基础方法到高级优化,系统梳理常见的2D碰撞检测技术,并提供可落地的实战建议。
一、基础几何形状的碰撞检测
1. 轴对齐包围盒(AABB, Axis-Aligned Bounding Box)
原理:AABB是最简单的碰撞检测方法,通过比较两个矩形在X轴和Y轴上的投影是否重叠来判断碰撞。
数学表达:
设矩形A的坐标为$(x_1, y_1, x_2, y_2)$(左下角与右上角),矩形B为$(x_3, y_3, x_4, y_4)$,则碰撞条件为:
优点:计算量小,适合动态物体多的场景(如角色移动)。
缺点:无法处理旋转矩形,需结合其他方法(如OBB)。
代码示例(JavaScript):
function checkAABBCollision(rectA, rectB) {return rectA.x < rectB.x + rectB.width &&rectA.x + rectA.width > rectB.x &&rectA.y < rectB.y + rectB.height &&rectA.y + rectA.height > rectB.y;}
2. 圆形碰撞检测
原理:通过比较两圆心距离与半径之和判断碰撞。
数学表达:
设圆A的圆心为$(x_1, y_1)$,半径为$r_1$;圆B为$(x_2, y_2)$,半径为$r_2$,则碰撞条件为:
优化:避免开方运算,改用平方比较:
适用场景:粒子系统、弹道轨迹等。
代码示例(Python):
import mathdef checkCircleCollision(circleA, circleB):dx = circleA['x'] - circleB['x']dy = circleA['y'] - circleB['y']distance_sq = dx*dx + dy*dyreturn distance_sq <= (circleA['radius'] + circleB['radius'])**2
二、多边形与复杂形状的碰撞检测
1. 分离轴定理(SAT, Separating Axis Theorem)
原理:若两个凸多边形在任意一条轴上的投影不重叠,则它们不相交。
步骤:
- 遍历两个多边形的每条边,计算其法线作为分离轴。
- 将两个多边形投影到分离轴上,检查投影区间是否重叠。
- 若所有轴的投影均重叠,则发生碰撞。
优点:可处理任意方向的凸多边形。
缺点:对凹多边形需先分解为凸多边形。
代码示例(伪代码):
```python
def projectPolygon(polygon, axis):
min_proj = max_proj = dot(polygon[0], axis)
for vertex in polygon[1:]:proj = dot(vertex, axis)min_proj = min(min_proj, proj)max_proj = max(max_proj, proj)
return (min_proj, max_proj)
def checkSATCollision(polyA, polyB):
axes = getNormals(polyA) + getNormals(polyB) # 获取所有分离轴
for axis in axes:
projA = projectPolygon(polyA, axis)
projB = projectPolygon(polyB, axis)
if not overlap(projA, projB):
return False
return True
```
2. 像素级碰撞检测(Per-Pixel Collision)
原理:通过比较两个精灵的透明像素区域判断碰撞。
实现步骤:
- 渲染两个物体到离屏缓冲区,禁用颜色写入,仅启用深度测试。
- 读取像素数据,检查重叠区域是否有非透明像素。
适用场景:精细碰撞需求(如平台游戏中的角色与地形)。
优化建议:
- 结合AABB预检测,减少像素级检测次数。
- 使用掩码纹理(Mask Texture)加速判断。
三、性能优化策略
1. 空间分区技术
- 四叉树(Quadtree):将2D空间递归划分为四个象限,仅检测同一分区内的物体。
- 网格分区(Grid):将场景划分为固定大小的网格,每个网格维护物体列表。
适用场景:大规模动态物体(如子弹、粒子)。
2. 粗检测与细检测结合
- 粗检测:使用AABB或圆形快速排除不可能碰撞的物体。
- 细检测:对可能碰撞的物体使用SAT或像素级检测。
案例:在《愤怒的小鸟》中,先用圆形检测鸟类与猪的碰撞,再用像素级检测精确碰撞点。
3. 惰性检测(Lazy Evaluation)
- 仅在物体位置或形状发生变化时更新碰撞信息。
- 适用于静态场景或低频更新物体。
四、实战建议
-
选择合适的方法:
- 简单矩形:优先用AABB。
- 圆形物体:使用圆形检测。
- 复杂形状:SAT或分解为凸多边形。
-
避免过度检测:
- 对远离屏幕的物体禁用碰撞检测。
- 使用“睡眠”机制(Sleeping)减少静止物体的计算。
-
调试工具:
- 可视化碰撞边界(如用红色框显示AABB)。
- 记录碰撞事件日志,便于问题排查。
-
物理引擎集成:
- 对复杂需求,可集成Box2D、Chipmunk等物理引擎。
- 注意引擎的坐标系与项目坐标系的转换。
五、总结
2D碰撞检测是游戏与交互应用的核心技术,其选择需平衡精度与性能。从基础的AABB到高级的SAT,再到像素级检测,开发者应根据场景需求灵活组合。通过空间分区、粗细检测结合等优化策略,可显著提升性能。最终,实战中的调试工具与物理引擎集成能进一步降低开发成本。掌握这些方法后,你将能高效实现从简单弹球到复杂平台游戏的物理交互。