【CSON原創】關於旋轉矩形的碰撞檢測


  在網上可以找到很多關於旋轉矩形碰撞檢測的方法,磚家也有文章對這種碰撞檢測作過分析:方向包圍盒(OBB)碰撞檢測。本文主要是對其中的細節加上一些自己的分析,並結合網上另外一些關於旋轉矩形碰撞檢測的資料,和大家一起探討實現的技術細節。

  首先推薦一個參考資料,里面對旋轉矩形碰撞檢測的解釋還是挺不錯的,並且同樣適用於其他多邊形碰撞檢測,點擊下載
  

  demo預覽:

  (拖動條調整矩形旋轉角度,鼠標點擊可移動紅色矩形,demo做得比較簡陋,大概湊合看吧,意思表達清楚了就行~)

 
60
30
 

 

 

 

 

 

 

  實現原理:

  對於兩個多邊形,如果存在一個軸,使得兩個多邊形的在該軸上的投影不重疊,則多邊形之間沒有碰撞發生。

  所有可能的軸為垂直於多邊形每個邊的軸。

 

  實現步驟:

  step1:獲取矩形的兩個軸。

 

  由於矩形對邊相互平行,因此平行的兩個邊共同擁有一條垂直於它們的軸。因此,對於每個矩形,需要用於檢測的軸只有兩條。我們只需要檢測在另一個矩形在該軸上的投影是否和該軸重疊。為了方便,我們可以直接拿矩形相鄰的兩個邊作為兩個軸,然后把這兩個軸和另一個矩形的四個邊作是否有重疊的比較:

 

var linesArr1=getFourLines(rect1.pointsArr);//矩形1的四個邊
var linesArr2=getFourLines(rect2.pointsArr);//矩形2的四個邊

//矩形相鄰的兩個邊作為兩個軸,並且和另一個矩形的四個邊進行投影重疊的比較
if(detectAxisCollision(linesArr2[0],linesArr1)&&detectAxisCollision(linesArr2[1],linesArr1)&&detectAxisCollision(linesArr1[0],linesArr2)&&detectAxisCollision(linesArr1[1],linesArr2)){
    return true;
}
return false;

 

  step2:獲取該軸在該向量上的投影以及獲取另一個矩形各個邊在該軸上的投影。

 

  要獲得線段在軸上的投影,我們需要分解為計算線段兩個頂點在軸上的投影。如何計算點在軸上的投影?這里附上公式:

 

//頂點在軸上的投影
var x=((p[0]*axis[0]+p[1]*axis[1])/(axis[0]*axis[0]+axis[1]*axis[1]))*axis[0];
var y=((p[0]*axis[0]+p[1]*axis[1])/(axis[0]*axis[0]+axis[1]*axis[1]))*axis[1];

  p為需要被投影的點,axis為投影的目標軸向量。由於之前我們已經把矩形的相鄰兩個邊作為矩形的軸,因此軸向量axis的計算可以為:

 

var axis=[L[1][0]-L[0][0],L[1][1]-L[0][1]];//軸向量 L為矩形的軸

  計算出兩個點的投影,就可以得到線段的投影了。

 

  step4:檢測每個邊在該向量上的投影是否和軸在該向量上的投影重疊。

 

  如何檢測線段的重疊?由於這里兩個線段是投影在同一個軸向量上,因此他們肯定平行,所以判別方法也比較簡單了。方法這里提供一個:線段端點的x軸坐標分別和另一線段的兩個端點的x軸坐標相減,得出的兩個結果相乘,如果存在結果小於0,則證明線段重疊(當兩個線段垂直的時候,使用端點的y軸坐標作判斷):

 

var isLineOverlap=function(l1,l2){//判斷線段是否重疊
    
    var l1p1=l1[0],l1p2=l1[1],l2p1=l2[0],l2p2=l2[1];
    if(l1p1[0]!=l2p1[0]){//非垂直X軸的兩線段
        if((l1p1[0]-l2p1[0])*(l1p1[0]-l2p2[0])<0||(l1p2[0]-l2p1[0])*(l1p2[0]-l2p2[0])<0||(l2p1[0]-l1p1[0])*(l2p1[0]-l1p2[0])<0||(l2p2[0]-l1p1[0])*(l2p2[0]-l1p2[0])<0){
            return true;
        }
    }
    else{//垂直X軸
        if((l1p1[1]-l2p1[1])*(l1p1[1]-l2p2[1])<0||(l1p2[1]-l2p1[1])*(l1p2[1]-l2p2[1])<0||(l2p1[1]-l1p1[1])*(l2p1[1]-l1p2[1])<0||(l2p2[1]-l1p1[1])*(l2p2[1]-l1p2[1])<0){        
            return true;
        }            
    }

    return false;
}

 

  step5:如果其中一個軸在向量上的投影和另一個矩形各個邊在該向量上的投影都不重疊,則沒有碰撞,否則產生碰撞。

  只要我們檢測到有一條軸和另一個矩形的四個邊的在該軸上的投影沒有重疊,則可以結束判斷,返回沒有碰撞了:

 

        //矩形相鄰的兩個邊作為兩個軸,並且和另一個矩形的四個邊進行投影重疊的比較
        if(detectAxisCollision(linesArr2[0],linesArr1)&&detectAxisCollision(linesArr2[1],linesArr1)&&detectAxisCollision(linesArr1[0],linesArr2)&&detectAxisCollision(linesArr1[1],linesArr2)){
            return true;
        }
        return false;

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM