不久以前在論壇上有人發貼,使用java編寫的超級馬里奧如何實現碰撞檢測,筆者本身之前html
也作過Tank大戰。裏面一樣涉及到碰撞檢測,翻翻U盤裏的東西還在,何時也給共享出來。java
這篇文章就簡單遊戲中的碰撞檢測作一個簡單的總結。首先需聲明的是這裏只是2D的碰撞檢測。算法
文章出處地址:http://blog.csdn.net/kiritor/article/details/8948097數組
對於形狀之間如何來判斷是不是碰撞的這要根據具體的形狀來定。在新手練手的小遊戲中,ide
物體形狀通常能夠設定爲矩形區域,這類規則圖形。它的碰撞檢測能夠經過java API中的優化
Rectangle類來實現碰撞的檢測。spa
首先咱們查看API關於Rectangle類的介紹:它就是指定座標空間的一個區域,這個區域是經過.net
指定左上角x、y座標和去高度和寬度來肯定的。htm
接下來看起具體的方法public Rectangleintersection(Rectangle r),這個方法就是碰撞檢測對象
的關鍵了,若是兩個Rectangle對象有交集,那麼他們就有碰撞了。而每一個形狀咱們均可以獲得他
們的Rectangle對象,這樣圖形的碰撞檢測也就得以實現了。
/* 判斷×××是否擊中障礙物 */ public boolean isHit(com.Alex.map.Map map) { boolean flag = true;// 表明沒有撞到 // 分類別的獲得全部的障礙物 List<Stuff> stuffList = new Vector<Stuff>(); stuffList.addAll(map.getBricks()); stuffList.addAll(map.getIrons()); stuffList.addAll(map.getWaters()); for (int i = 0; i < stuffList.size(); i++) { Stuff a = stuffList.get(i); Rectangle tankRectangle = new Rectangle(bullet2.getRec()); Rectangle stuffRectangle = new Rectangle(a.getX(), a.getY(), 20, 20); if (stuffRectangle.intersects(tankRectangle)) { flag = false;// 撞到了 break; } } return flag; }
上述這個例子就是判斷Tank發出的×××是否對地圖中的障礙物有碰撞,若是有的話
就作相關的操做(×××爆炸、障礙物消失)。上述代碼中×××對象有一個getRec()方法就是
獲得×××圖形的Rectangle對象,具體實現就是根據其座標和width、height來生成的。
採用此種方法進行碰撞檢測須要注意,對於圖片的實現處理應該儘可能的去掉圖標邊角
的空白,否則實際效果能夠產生肉眼可辨的偏差。也就是說Rectangle儘可能的包住圖形
且Rectangle的區域儘可能小。這種碰撞檢測的方法被稱之爲多矩形碰撞。
一旦有一個矩形數組中的矩形與另一個矩形數組的矩形發生碰撞就可認爲發生了
多矩形碰撞。其中多圓形碰撞也是一樣的道理,只是包裹的圖形區域是圓形罷了。
不過仔細思考多矩形碰撞一樣會有偏差,雖然這種偏差十分小。
像素級別的碰撞檢測算得上是最精確的碰撞檢測方法了。
首先遍歷算出一張位圖全部的像素點座標,而後與另一張位圖上的全部點座標進行對比,
一旦有一個像素點的座標相同,就馬上取出這兩個座標相同的像素點,經過位運算取出這兩個
像素點的最高位(透明度)進行對比,若是兩個像素點都是非透明像素則斷定這兩張位圖發生
碰撞。
介紹了像素碰撞以後能夠獲得兩個結論:
一、像素碰撞很精確,不論位圖之間是否帶有透明像素,均可以精確判斷;
二、正是由於像素碰撞的這種高精確斷定,從而也會形成代碼效率明顯下降!
假設兩張100×100 大小的位圖利用像素級檢測碰撞,僅是遍歷兩張位圖的像素
就要循環100×100×2=20000 句邏輯代碼;何況還要對篩選出來的相同座標的
像素點進行遍歷對比其透明值!這種效率可想而知!
固然,這裏的像素碰撞只是大體提供一種思路,確定還能夠進行代碼優化;可是不論再優的
代碼,使用像素級進行碰撞檢測終會致使整個程序的運行效率大大下降。所以像素級別的碰
撞檢測在遊戲開發中是儘可能避免使用的!
對於×××和障礙物的碰撞檢測,採用上述第一種方法就能夠簡單的實現了,不過×××
是圓形的有沒有更加精確的碰撞檢測方法呢?也就是實現圓形和矩形的碰撞檢測嘛。
這裏咱們須要簡單的運行下幾何數學的知識,給個簡單的圖就會明白了。
小圓有個運動軌跡,軌跡的線若是和他對着的正方形的相對某一象限的邊有焦點,那麼
就能碰撞,邊就是那一個象限的邊(還要把圓半徑算進去),具體代碼就不實現了,讀者可
本身嘗試着去實現。
對於矩形碰撞,不少人都知道。但面對多邊形圖形,大多數採用多矩形覆蓋的方式。
SAT 一種能夠快速檢測不規則的凸多邊形是否碰撞的算法給出兩個凸多邊形體,
若是咱們能找到一個軸線,使兩物體在此軸線上的投影不重疊,則這兩個物體之間沒有
發生碰撞,這個軸線叫作Separating Axis(紅色軸線)。
對於2D來講,紅色線就是垂直與多邊形邊的軸。
所以,若是咱們要檢查兩多邊形是否碰撞,就去檢查兩多邊形在每一個全部可能的軸上的投影
是否重疊。
/// 檢測2個矩形是否發生碰撞 /// </summary> /// <returns></returns> public static bool IsIntersect (Vector2[] A, Vector2[] B) { Vector2 AX, AY, BX, BY; AX = new Vector2(); AY = new Vector2(); BX = new Vector2(); BY = new Vector2(); AX.X = A[0].X - A[1].X; AX.Y = A[0].Y - A[1].Y; AY.X = A[0].X - A[3].X; AY.Y = A[0].Y - A[3].Y; BX.X = B[0].X - B[1].X; BX.Y = B[0].Y - B[1].Y; BY.X = B[0].X - B[3].X; BY.Y = B[0].Y - B[3].Y; //對於AX上: if (Tmp(AX, A, B)) return false; if (Tmp(AY, A, B)) return false; if (Tmp(BX, A, B)) return false; if (Tmp(BY, A, B)) return false; return true; } private static bool Tmp(Vector2 IS,Vector2[] A,Vector2[] B) { float[] v = new float[4]; for (int i = 0; i < 4; i++) { float tmp = (IS.X * A[i].X + IS.Y * A[i].Y) / (IS.X * IS.X + IS.Y * IS.Y); v[i] = tmp * IS.X * IS.X + tmp * IS.Y * IS.Y; } float[] vv = new float[4]; for (int i = 0; i < 4; i++) { float tmp = (IS.X * B[i].X + IS.Y * B[i].Y) / (IS.X * IS.X + IS.Y * IS.Y); vv[i] = tmp * IS.X * IS.X + tmp * IS.Y * IS.Y; } if (Math.Max(Math.Max(v[0], v[1]),Math.Max(v[2],v[3])) >Math.Min(Math.Min(vv[0],vv[1]),Math.Min(vv[2],vv[3])) && Math.Min(Math.Min(v[0],v[1]),Math.Min(v[2],v[3])) < Math.Max(Math.Max(vv[0],vv[1]),Math.Max(vv[2],vv[3]))) { return false; }//表示暫時不知道是否碰撞 else return true;//表示知道未碰撞 }