您好,登錄后才能下訂單哦!
不久之前在論壇上有人發(fā)貼,使用java編寫(xiě)的超級(jí)馬里奧如何實(shí)現(xiàn)碰撞檢測(cè),筆者自己以前
也做過(guò)Tank大戰(zhàn)。里面同樣涉及到碰撞檢測(cè),翻翻U盤(pán)里的東西還在,什么時(shí)候也給共享出來(lái)。
這篇文章就簡(jiǎn)單游戲中的碰撞檢測(cè)做一個(gè)簡(jiǎn)單的總結(jié)。首先需聲明的是這里只是2D的碰撞檢測(cè)。
文章出處地址:http://blog.csdn.net/kiritor/article/details/8948097
對(duì)于形狀之間如何來(lái)判斷是否是碰撞的這要根據(jù)具體的形狀來(lái)定。在新手練手的小游戲中,
物體形狀一般可以設(shè)定為矩形區(qū)域,這類規(guī)則圖形。它的碰撞檢測(cè)可以通過(guò)java API中的
Rectangle類來(lái)實(shí)現(xiàn)碰撞的檢測(cè)。
首先我們查看API關(guān)于Rectangle類的介紹:它就是指定坐標(biāo)空間的一個(gè)區(qū)域,這個(gè)區(qū)域是通過(guò)
指定左上角x、y坐標(biāo)和去高度和寬度來(lái)確定的。
接下來(lái)看起具體的方法public Rectangleintersection(Rectangle r),這個(gè)方法就是碰撞檢測(cè)
的關(guān)鍵了,如果兩個(gè)Rectangle對(duì)象有交集,那么他們就有碰撞了。而每個(gè)形狀我們都可以得到他
們的Rectangle對(duì)象,這樣圖形的碰撞檢測(cè)也就得以實(shí)現(xiàn)了。
/* 判斷×××是否擊中障礙物 */ public boolean isHit(com.Alex.map.Map map) { boolean flag = true;// 代表沒(méi)有撞到 // 分類別的得到所有的障礙物 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; }
上述這個(gè)例子就是判斷Tank發(fā)出的×××是否對(duì)地圖中的障礙物有碰撞,如果有的話
就做相關(guān)的操作(×××爆炸、障礙物消失)。上述代碼中×××對(duì)象有一個(gè)getRec()方法就是
得到×××圖形的Rectangle對(duì)象,具體實(shí)現(xiàn)就是根據(jù)其坐標(biāo)和width、height來(lái)生成的。
采用此種方法進(jìn)行碰撞檢測(cè)需要注意,對(duì)于圖片的實(shí)現(xiàn)處理應(yīng)該盡量的去掉圖標(biāo)邊角
的空白,不然實(shí)際效果可以產(chǎn)生肉眼可辨的誤差。也就是說(shuō)Rectangle盡量的包住圖形
且Rectangle的區(qū)域盡量小。這種碰撞檢測(cè)的方法被稱之為多矩形碰撞。
一旦有一個(gè)矩形數(shù)組中的矩形與另外一個(gè)矩形數(shù)組的矩形發(fā)生碰撞就可認(rèn)為發(fā)生了
多矩形碰撞。其中多圓形碰撞也是同樣的道理,只是包裹的圖形區(qū)域是圓形罷了。
不過(guò)仔細(xì)思考多矩形碰撞同樣會(huì)有誤差,雖然這種誤差十分小。
像素級(jí)別的碰撞檢測(cè)算得上是最精確的碰撞檢測(cè)方法了。
首先遍歷算出一張位圖所有的像素點(diǎn)坐標(biāo),然后與另外一張位圖上的所有點(diǎn)坐標(biāo)進(jìn)行對(duì)比,
一旦有一個(gè)像素點(diǎn)的坐標(biāo)相同,就立刻取出這兩個(gè)坐標(biāo)相同的像素點(diǎn),通過(guò)位運(yùn)算取出這兩個(gè)
像素點(diǎn)的最高位(透明度)進(jìn)行對(duì)比,如果兩個(gè)像素點(diǎn)都是非透明像素則判定這兩張位圖發(fā)生
碰撞。
介紹了像素碰撞之后可以得到兩個(gè)結(jié)論:
1、像素碰撞很精確,不論位圖之間是否帶有透明像素,都可以精確判斷;
2、正是因?yàn)橄袼嘏鲎驳倪@種高精確判定,從而也會(huì)造成代碼效率明顯降低!
假設(shè)兩張100×100 大小的位圖利用像素級(jí)檢測(cè)碰撞,僅是遍歷兩張位圖的像素
就要循環(huán)100×100×2=20000 句邏輯代碼;況且還要對(duì)篩選出來(lái)的相同坐標(biāo)的
像素點(diǎn)進(jìn)行遍歷對(duì)比其透明值!這種效率可想而知!
當(dāng)然,這里的像素碰撞只是大致提供一種思路,肯定還可以進(jìn)行代碼優(yōu)化;但是不論再優(yōu)的
代碼,使用像素級(jí)進(jìn)行碰撞檢測(cè)終會(huì)導(dǎo)致整個(gè)程序的運(yùn)行效率大大降低。因此像素級(jí)別的碰
撞檢測(cè)在游戲開(kāi)發(fā)中是盡量避免使用的!
對(duì)于×××和障礙物的碰撞檢測(cè),采用上述第一種方法就可以簡(jiǎn)單的實(shí)現(xiàn)了,不過(guò)×××
是圓形的有沒(méi)有更加精確的碰撞檢測(cè)方法呢?也就是實(shí)現(xiàn)圓形和矩形的碰撞檢測(cè)嘛。
這里我們需要簡(jiǎn)單的運(yùn)行下幾何數(shù)學(xué)的知識(shí),給個(gè)簡(jiǎn)單的圖就會(huì)明白了。
小圓有個(gè)運(yùn)動(dòng)軌跡,軌跡的線如果和他對(duì)著的正方形的相對(duì)某一象限的邊有焦點(diǎn),那么
就能碰撞,邊就是那一個(gè)象限的邊(還要把圓半徑算進(jìn)去),具體代碼就不實(shí)現(xiàn)了,讀者可
自己嘗試著去實(shí)現(xiàn)。
對(duì)于矩形碰撞,很多人都知道。但面對(duì)多邊形圖形,大多數(shù)采用多矩形覆蓋的方式。
SAT 一種可以快速檢測(cè)不規(guī)則的凸多邊形是否碰撞的算法給出兩個(gè)凸多邊形體,
如果我們能找到一個(gè)軸線,使兩物體在此軸線上的投影不重疊,則這兩個(gè)物體之間沒(méi)有
發(fā)生碰撞,這個(gè)軸線叫做Separating Axis(紅色軸線)。
對(duì)于2D來(lái)說(shuō),紅色線就是垂直與多邊形邊的軸。
因此,如果我們要檢查兩多邊形是否碰撞,就去檢查兩多邊形在每個(gè)所有可能的軸上的投影
是否重疊。
/// 檢測(cè)2個(gè)矩形是否發(fā)生碰撞 /// </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; //對(duì)于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; }//表示暫時(shí)不知道是否碰撞 else return true;//表示知道未碰撞 }
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。