檢測凸多邊形碰撞的一種簡單的方法是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的網站: