多邊形碰撞 -- SAT方法

檢測凸多邊形碰撞的一種簡單的方法是SAT(Separating Axis Theorem),即分離軸定理ide

 

原理:將多邊形投影到一條向量上,看這兩個多邊形的投影是否重疊。若是不重疊,則認爲這兩個多邊形是分離的,不然找下一條向量來繼續投影。咱們不須要比較不少條向量,由於已經在數學上證實,多邊形每條邊的垂直向量就是咱們須要的向量。優化

 

1.AABB網站

讓咱們首先以AABB開始(AABB是一種兩邊分別平行於X-Y軸的矩形)spa

判斷兩個AABB是否碰撞,咱們只須要投影兩次,分別是投影在平行於X軸和Y軸的向量上debug

由上圖能夠看見,由於在Y軸方向的投影是分離的,所以能夠直接得出結論,即這兩個AABB是分離的。3d

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;
}

 效果:---點擊運行---code

(點擊產生AABB,碰撞的變紅,不然變黃)orm

 

 

2.圓htm

圓的碰撞檢測也能用SAT,就是要把兩個圓投影在兩個圓心連線的向量上。比較半徑和與圓心距離,若是半徑和大於圓心距離則碰撞。blog

代碼:

注:一般爲了優化,都是用平方而不是開方(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

相關文章
相關標籤/搜索