菜鸡UI仔 通过SAT进行2D物体的精细碰撞检测 什么是SAT 通过上图我们能比较清除的了解到,所谓的SAT分离轴定理就是通过不停的转换投影角度,如果所有的投影都没有缝隙存在那么,那么这两个物体就发生了碰撞,反之就没有发生碰撞。基础的原理我们确定了,接下来我们就展示如何通过代码实现这个定理。 实现SAT检测 确定投影轴 虽然我们在定理中说的是任意投影角度,但显然我们在程序中无进行无限的投影尝试,那么第一步我们就要确定检测投影的次数和投影的角度。 投影检测次数通过上图就可以看出来,很容易确定就是两个凸多边形的边数之和,次数确定了,那么方向怎么确定呢? 通过上图可以知道,投影的方向及投影轴即为每条边的法向量,法向量怎么求呢,通过向量点积的意义我们可以知道如果两个向量互相垂直那么他的点积为0,所以比如上图的边为(p1,p2)那么他的法向量就是(p2,-p1)–(当然反过来也对,只是会决定法向量的朝向) 确定多边形的投影 我们已经知道向量的点积的物理意义为一个向量到另一个向量的投影,但是这个投影是个标量,并不能表示投影在坐标系内的实际位置,那么要怎么确定位置呢? 我们可以通过计算每个原点到改多边形的点的向量到对应投影轴的距离,然后取其中的最大值和最小值来表示改投影是在该投影轴上,距离原点多少距离长度多少的一个投影轴,这样就能确定该投影在坐标系中的具体位置了,这样就可以对投影进行对比。如果A投影的最大值比B的投影的最小值大 且 B投影的最大值比A投影的最小值大 那么两个多边形在改投影轴的投影存在重叠。这样对每个投影轴进行投影对比,看投影是否存在分离间隙就能知道是否发生重叠碰撞,及 分离轴定理。 圆形和多边形 那么圆形和多边形是怎么判断的呢? 通过上图可以知道,唯一特殊的地方就在于对于圆来说如何确定他的投影轴,其实也很简单,圆的投影轴就为圆心到另一个多边形离圆心最近的点的向量的法向量。确定好投影轴后其他的判断逻辑跟两个多边形的是一样的。 碰撞之后的处理 那么发生碰撞之后我们该如何处理呢? 这里说明一个最简单最基础的行为,就是把两个物体分开,分开到刚好不碰撞的位置–(其他的比如弹飞啥的,都可以在这个的基础上进行修改)。 那么为了分离两个碰撞中的物体,我们就要知道一个概念MIT(最小平移量) 我们只需要讲碰撞的物体,进行碰撞反方向的一半(为什么是一半呢,应为碰撞是两个物体发生的,他们需要各自往后退一步,那么就是一半)的MIT的位移,那么就是刚好恢复到不碰撞阶段,如果碰撞的物体其中一个为固定物体,类似Unity中没有rigidbody或者关掉isKinemics的飞动力学物体,那么另一个物体就要进行一整个MIT的位移。 那么知道了MIT的概念后我们需要怎么求呢,其实聪明的小伙伴已经发现了,这个MIT其实我们在进行SAT计算的时候已经算过了,这个MIT就是所有投影轴投影中投影重叠最小的那个距离,我们只需要在计算的时候进行比对然后记录下来就可以。 其他吐槽🙈 按照这个逻辑编写完成后再Unity里面运行,如果被碰撞的物体 (比如正方形)碰撞部位为一个点的时候,一直用另为一个(非运动学)物体去碰撞他,会出现抖动情况(其实Unity自带的也会有这个情况,但是不明显),目前还没太搞懂为啥会这样,猜测可能是float精度问题,Unity里面效果不明显可能是位置缓冲啥的做的比较好(猜测💀) 本文的图片全部来自于“等一下,我碰!”这篇文章中的内容,改文章中还介绍了其他的2D检测方法,感兴趣的可以自己查看