我們在游戲開發中總會遇到這樣那樣的碰撞,並且會很頻繁的去處理這些行為.這也是游戲開發的一種基本的算法.2D的相對3D的要簡單的多了,最簡單的就是矩形碰撞\圓形碰撞,像素碰撞。矩形碰撞用的最多
我就簡單總結一點我的認識,對於矩形碰撞 我們就把游戲中的角色統稱為一個一個的Actor,並且把每個 Actor框成一個與角色大小相等的矩形框,那麼在游戲中每次的循環檢查就是圍繞每個Actor的矩形框之間是否發生了交錯。為了簡單起見,我們就拿一個主角與一個Actor來分析,其它的可以類似。
主要分兩種檢測方法:(1)、使用.boolean collidesWith(Sprite s/TIEldLayer t, boolean pixelLevel) 判斷是否與另一個Sprite發生碰撞,第二個參數為true,認為不透明點發生了碰撞才算碰撞,否則認為矩形發生了碰撞就算碰撞,此方法用起來比較容易,但是很多時候真正使用起來,這種碰撞檢測方法是很不實用的。(2)另外一種是通過通過不同對象的坐標的關系來自己動手編寫適當方法,從而進行碰撞檢測。
下面對第二種方法進行詳細說明:
一個主角與一個Actor的碰撞其實就成了兩個矩形的檢測,是否發生了交集。
第一種方法:
我們可以通過檢測一個矩形的4個頂點是否在另外一個矩形的內部來完成。代碼如下:
我們簡單的設定一個Actor類:
public class Actor {
int x,y,w,h;
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getActorWidth() {
return w;
}
public int getActorHeight() {
return h;
}
檢測的處理為:
public boolean isCollidingWith (int px ,int py){
if(px > getX() && px < getX() + getActorWidth()
&& px > getY() && px < getY() + getActorHeight())
return true;
return false;
}
public boolean isCollidingWith(Actor another) {
if(isCollidingWith(another.getX(),another.getY())
||isCollidingWith(another.getX()+ another.getActorWidth(),another.getY())
||isCollidingWith(another.getX(),another.getY()+another.getActorHeight())
||isCollidingWith(another.getX()+ another.getActorWidth(),another.getY()+another.getActorHeight())
)
return true;
return false;
}
以上處理運行應該是沒有什麼問題的,但是沒有考慮不到運行速度,而游戲中需要大量的碰撞檢測工作,所以要求碰撞檢測要盡量的快。
第二種方法:
我們從相反的角度考慮,以前是想什麼時候相交,現在我們處理什麼時候不會相交,可以處理4條邊,
a b
左邊a矩形的右邊界在b矩形的左邊界以外,同理,a的上邊界需要在b的下邊界以外,四邊都判斷,則可以知道a是否與b相交,代碼:
/**
* ax a矩形左上角x坐標
* ay--a矩形左上角y坐標
* aw -- a矩形寬度
* ah -- a矩形高度
*
* bx --b矩形左上角x坐標
* by --b矩形左上角y坐標
* bw-- b矩形寬度
* bh -- b矩形高度
* *
*/
public boolean isColliding(int ax,int ay,int aw,int ah,
int bx, int by, int bw, int bh){
if(ay > by + bh || by > ay + ah
|| ax > bx + bw || bx > ax + aw)
return false;
return true;
}
此方法比第一種簡單且運行快。
第三種方法:
這種方法其實可以說是第二種的一個變異,我們可以保存兩個矩形的左上和右下兩個坐標的坐標值,然後對兩個坐標的一個對比就可以得出兩個矩形是否相交。這應該比第二種更優越一點。
/*
* rect1[0]: 矩形1左上角x坐標
* rect1[1]: 矩形1左上角y坐標
* rect1[2]: 矩形1右下角x坐標
* rect1[3]: 矩形1右上角y坐標
*
* rect2[0]: 矩形2左上角x坐標
* rect2[1]: 矩形2左上角y坐標
* rect2[2]: 矩形2右下角x坐標
* rect2[3]: 矩形2右上角y坐標
*/
static boolean IsRectCrossing (int rect1[], int rect2[])
{
if (rect1[0] > rect2[2]) return false;
if (rect1[2] < rect2[0]) return false;
if (rect1[1] > rect2[3]) return false;
if (rect1[3] < rect2[1]) return false;
return true;
}
這種速度應該很快的了,推薦使用這種。
第四種方法:(類似於圓形與圓形)
現在介紹一種測試兩個對象邊界是否重疊。可以通過比較兩個對象間的距離和兩個對象半徑的和的大小,很快實現這種檢測。如果它們之間的距離小於半徑的和,就說明產生了碰撞。
為了計算半徑,就可以簡單的取高度或者寬度的一半作為半徑的值。
代碼如下:
public static boolean isColliding ( int ax,int ay,int aw, int ah,
int bx, int by, int bw, int bh){
int r1 = (Math.max(aw, ah)/2 + 1);
int r2 = (Math.max(bw, bh)/2 + 1);
int rSquard = r1 * r1;
int anrSquard = r2* r2;
int disX = ax - bx;
int disY = ay - by;
if((disX * disX) + (disY * disY) < (rSquard + anrSquard))
return true;
else
return false;
}
這種方法類似於圓形碰撞檢測。處理兩個圓的碰撞處理就可以用這種。
以上只是總結了幾種簡單的方法,當然其實在游戲中熟練的運用才是最好的,在J2ME中差不多以上幾種算夠了,它不需要太精密的算法,當然可能有些需要比以上更復雜,例如如果一個對象速度足夠快的,可能只經歷一步就穿越了一個本該和它發生碰撞的對象,如果要考慮這種的話就要根據它的運動路徑來處理。還有可能碰到不同的邊界發生不同的行為,這就要具體的對碰撞行為進行解剖,然後具體處理。
總之,可能游戲中遇到的碰撞行為會更復雜,還需要更進一步的學習。