多边形碰撞 -- SAT方法

检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理。

原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠。如果不重叠,则认为这两个多边形是分离的,否则找下一条向量来继续投影。我们不需要比较很多条向量,因为已经在数学上证明,多边形每条边的垂直向量就是我们需要的向量。

1.AABB

让我们首先以AABB开始(AABB是一种两边分别平行于X-Y轴的矩形)

判断两个AABB是否碰撞,我们只需要投影两次,分别是投影在平行于X轴和Y轴的向量上

由上图可以看见,因为在Y轴方向的投影是分离的,因此可以直接得出结论,即这两个AABB是分离的。

function AABBvsAABB(aabb1, aabb2) {
    //check X axis
    if(aabb1.xMin > aabb2.xMax)
        return false;
    if(aabb1.xMax < aabb2.xMin)
        return false;
    //check Y axis
    if(aabb1.yMin > aabb2.yMax)
        return false;
    if(aabb1.yMax < aabb2.yMin)
        return false;

    return true;
}

效果:---点击运行---

(点击产生AABB,碰撞的变红,否则变黄)

2.圆

圆的碰撞检测也能用SAT,就是要把两个圆投影在两个圆心连线的向量上。比较半径和与圆心距离,如果半径和大于圆心距离则碰撞。

代码:

注:通常为了优化,都是用平方而不是开方(sqrt好慢的)

function CircleVsCircle(c1, c2) {
    var xSqr = c1.centerX - c2.centerX;
    xSqr *= xSqr;
    var ySqr = c1.centerY - c2.centerY;
    ySqr *= ySqr;
    //get the distance^2
    var distanceSqr = xSqr + ySqr;

    var radiusSum = c1.radius + c2.radius;

    if(distanceSqr <= radiusSum*radiusSum)
        return true;
    else
        return false;
}

效果:---点击运行---

(点击产生圆)

3.多边形

(1)找出两个多边形所有边的垂直向量;

(2)将两个多边形投影到垂直向量上,判断投影是否相交,如果不相交则两个多边形不相交,否则选下一条垂直向量继续进行投影判断。

代码:

function PolyVsPoly(p1, p2) {
    //check the normal in p1
    for(var i = 0; i < p1.points.length-1; i++) {
        var edge = Minus(p1.points[i], p1.points[i+1]);
        var normal = Normal(edge);

        var isOverlap = CheckCollide(normal, p1, p2);
        if(!isOverlap)
            return false;
    }

    //check normal in p2
    for(var i = 0; i < p2.points.length-1; i++) {
        var edge = Minus(p2.points[i], p2.points[i+1]);
        var normal = Normal(edge);

        var isOverlap = CheckCollide(normal, p1, p2);
        if(!isOverlap)
            return false;
    }

    return true;
}

function CheckCollide(axis, p1, p2) {
    var min1 = Dot(p1.points[0], axis);
    var max1 = Dot(p1.points[0], axis);
    for(var k = 1; k < p1.points.length; k++) {
        var v = Dot(p1.points[k], axis);
        if(v > max1)
            max1 = v;
        if(v < min1)
            min1 = v;
    }

    var min2 = Dot(p2.points[0], axis);
    var max2 = Dot(p2.points[0], axis);
    for(var k = 1; k < p2.points.length; k++) {
        var v = Dot(p2.points[k], axis);
        if(v > max2)
            max2 = v;
        if(v < min2)
            min2 = v;
    }

    if(!IsOverlap(min1, max1, min2, max2))
        return false;

    return true;
}

效果:---点击运行---

(使用方向键来移动,碰撞的变红,否则变黄)

4.圆与多边形

(1)找出多边形每条边的垂直向量

(2)将圆和多边形投影到垂直向量上,再进行判断。

(其实和多边形之间的碰撞很像,这里就不浪费篇幅了)

总结:

SAT很简单,就是投影 + 重叠判断。

SAT只适用于凸体,毕竟凹体中间空缺的部分在投影后信息就消失了。

一些关于SAT的网站:

http://gamedevelopment.tutsplus.com/tutorials/collision-detection-with-the-separating-axis-theorem--gamedev-169

时间: 2024-12-28 11:34:02

多边形碰撞 -- SAT方法的相关文章

解决Hash碰撞冲突方法总结

我们知道,对象Hash的前提是实现equals()和hashCode()两个方法,那么HashCode()的作用就是保证对象返回唯一hash值,但当两个对象计算值一样时,这就发生了碰撞冲突.如下将介绍如何处理冲突,当然其前提是一致性hash. 1.开放地址法 开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,-,k(k<=m-1)其中,m为哈希表的表长.di 是产生冲突的时候的增量序列.如果di值可能为1,2,3,-m-1,称线性探测再散列.如果di取1,则每次冲突之后

判断点是否任意多边形内的2种方法

导入 判断触摸点是否在一个多边形的内部 方法 1.数学方法 这个方法的好处是任意平台都可以使用,不仅现于Android 算法: 求解通过该点的水平线与多边形各边的交点,单边交点为奇数,则成立 ok我们其实就是需要看这个点的单边射线与多边形的交点,代码实现如下: [java] view plaincopyprint? public boolean isInPolygon(Point point, Point[] points, int n) { int nCross = 0; for (int i

H5游戏开发之多边形碰撞检测

2D多边形碰撞检测介绍这是一篇论证如何在2D动作游戏中执行碰撞检测的文章(Mario,宇宙入侵者等),为了保证它的高效性和精确性,碰撞检测是以多边形为基础的,而不是以sprite为基础.这是两种不同的设计途径.基于sprite的检测执行的是检测sprites的像素的交叉,以这种方式来检测碰撞.多边形是使用向量数学来精确的计算点,时间和碰撞的方向.当多边形只是一种近似sprite自身的时候,它就超越了sprite系统.表现出了更精确的物理现象,例如弹性,摩擦,在一个随机的形状中来处理斜坡.碰撞检测

多线程之碰撞小球

弹球游戏是一款模拟多线程运行的游戏,利用继承Thread实现多线程. 效果图:小球之间会相互碰撞并交换速度在弹开.按钮能实现随机添加.移除小球并暂停小球移动. 具体实现: 1.创建界面(包含主函数). public class BallFrame extends JFrame {public static void main(String[] args) { BallFrame bf = new BallFrame(); bf.initUI(); } public void initUI(){

利用向量积(叉积)计算三角形的面积和多边形的面积

利用向量积(叉积)计算三角形的面积和多边形的面积: 向量的数量积和向量积: (1)  向量的数量积   (1)  向量的向量积 两个向量a和b的叉积(向量积)可以被定义为: 在这里θ表示两向量之间的角夹角(0° ≤ θ ≤ 180°),它位于这两个矢量 所定义的平面上. 向量积的模(长度)可以解释成以a和b为邻边的平行四边形的面积.求三角形ABC的面积,根据向量积的意义,得到: a=axi+ayj+azk; b=bxi+byj+bzk; a×b=(aybz-azby)i+(azbx-axbz)j

如何利用框选工具获取多边形范围?

我在地图上画了个框,如何知道他的面积,各个顶点的经纬度呢?我们需要用到鼠标工具插件,AMap.MouseTool. 首先,插件的使用方法分为同步和异步.我们以同步加载插件的方法为例. <script src="http://webapi.amap.com/maps?v=1.3&key=您的Key&plugin=AMap.MouseTool"></script> <script> var mouseTool = new AMap.Mou

Chipmunk碰撞回调短时间内重入的解决办法

Chipmunk引擎中碰撞行为可能在细微处与一般认识略有不同. 比如碰撞回调方法可能会重入.不知道方法(函数)重入概念的童鞋可以自行谷哥或度娘. 第一次碰撞方法还未返回,第二次碰撞回调又被调用了.至于它们是否运行在同一线程,这个不知道.至少我调试中都在一个线程里.但在一个线程里也会发生重入.这里研究的不深入,有错误请指出. 最开始碰撞回调方法如下: -(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair star:(CCNode

unity触发器和碰撞器

Unity中检测碰撞的方法有两种,一种是触发器一种是碰撞器,现在我来解释一下两种的区别. 触发器:有三种方法,分别是OnTriggerEnter,OnTriggerStay,OnTriggerExit 触发器一般是触发某种事物时使用,例如计分,过关什么的,不带有碰撞的物理效果. 碰撞器:有三种方法,分别是OnCollisionEnter,OnCollisionStay,OnCollisionExit 碰撞器一般是碰撞某种事物时使用,例如撞车,击中目标,带有碰撞的物理效果. 代码: 触发器: 1

太帅气啦~多边形教程哦,转载~

低多边形(Low-Poly)字体设计是目前最新.最火的一个设计趋势.低多边形字体设计主要是基于有少量多边形的3D网格,同时结合一些渲染技术和灯光效果,使这些网格看上去像纸工艺或折纸作品. 低多边形通常需要使用3D软件来实现,但这篇教程将教会大家如何使用基本的PS工具来实现它的2D简化版,同时为了使低多边形效果更加精美,我们会用到一个非常简单的App- Image Triangulator App(别急哟,下方会有下载地址).以下为神器的部分功能和成果展现:) 多边形是今年很火的一种设计,同学们也