2D 物理引擎基础之碰撞检测
一、前言 本篇是“2D物理引擎基础”的第二篇文章,将主要讲解碰撞检测的基本原理和算法。 碰撞检测是物理引擎十分重要的组成部分。碰撞检测及后续的碰撞约束反映了物质的不可入性,是物理模拟真实性的基础。另外碰撞检测也能有效用于游戏逻辑的实现,如触发陷阱、探测障碍等等。 二、碰撞检测的基本概念 碰撞检测的目标就是判断两个几何体是否存在重合部分,如果存在重合部分,则得到接触点、碰撞法线和穿透深度。 接触点(Contact Point)指的是两个几何体相接触的位置。当然对于碰撞检测而言,接触的部分并非点而是区域,但是我们可以通过算法从中近似地取出接触点,一般位于其中一个几何体的顶点或边上。 碰撞法线指示了一个物体与另一个物体发生碰撞后,后者为了分离而应该采取的运动方向。这一法线大多是几何体中某一条边的法线 穿透深度是沿碰撞法线方向最终分离所需的距离,这一数值常用来修正碰撞后两几何体的位置,避免两几何体在视觉上发生重叠。 三、分离轴定理(SAT,Separating Axis Theorem) 分离轴定理是如下内容:若两个凸物体没有重合,则总会存在一条直线,能将两个物体分离。这样的直线称为分离轴。对于高维物体来说这同样适用,只不过分离轴将变为分离超平面。 利用分离轴定理可以实现凸几何体的碰撞检测。对于多边形,算法是这样的: 对两个多边形的每一条边,做垂直于该边的直线 对两个多边形的每一个顶点,分别做到步骤1中所得直线的投影 如果存在一条直线,两个多边形对这条直线的投影并不重合,则两个多边形不重合 如果不存在步骤3中的直线,则两个多边形重合。 完全按照算法思路得到代码如下 def sat(body_a, body_b): return not find_separate_axis(body_a, body_a, body_b) and not find_separate_axis(body_b, body_a, body_b) def find_separate_axis(lines_body, body_a, body_b): for i in range(len(lines_body) - 1): p1 = lines_body[i] p2 = lines_body[i] + get_normal(lines_body[i+1] - lines_body[i]) a_min, a_max = body_cast(p1, p2, body_a) b_min, b_max = body_cast(p1, p2, body_b) if p1[0] != p2[0]: max_min = a_min if a_min[0] > b_min[0] else b_min min_max = a_max if a_max[0] < b_max[0] else b_max if max_min[0] < min_max[0]: continue else: max_min = a_min if a_min[1] > b_min[1] else b_min min_max = a_max if a_max[1] < b_max[1] else b_max if max_min[1] < min_max[1]: continue return True return False def body_cast(a, b, body): body_min = body_max = point_cast(a, b, body[0]) for p in body: p_cast = point_cast(a, b, p) if p_cast[0] < body_min[0] or (p_cast[0] == body_min[0] and p_cast[1] < body_min[1]): body_min = p_cast if p_cast[0] > body_max[0] or (p_cast[0] == body_max[0] and p_cast[1] > body_max[1]): body_max = p_cast return body_min, body_max def point_cast(a, b, p): u = p - a v = b - a p_cast = a + v * (np....