溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

發(fā)布時(shí)間:2020-10-03 09:48:14 來(lái)源:網(wǎng)絡(luò) 閱讀:8298 作者:kiritor 欄目:開(kāi)發(fā)技術(shù)

前言

    不久之前在論壇上有人發(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

碰撞檢測(cè)

    對(duì)于形狀之間如何來(lái)判斷是否是碰撞的這要根據(jù)具體的形狀來(lái)定。在新手練手的小游戲中,

 物體形狀一般可以設(shè)定為矩形區(qū)域,這類規(guī)則圖形。它的碰撞檢測(cè)可以通過(guò)java API中的

  Rectangle類來(lái)實(shí)現(xiàn)碰撞的檢測(cè)。

 規(guī)則圖形碰撞檢測(cè)(Rectangle)

    首先我們查看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)了。

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

/* 判斷×××是否擊中障礙物 */
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è)的方法被稱之為多矩形碰撞。


Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

          一旦有一個(gè)矩形數(shù)組中的矩形與另外一個(gè)矩形數(shù)組的矩形發(fā)生碰撞就可認(rèn)為發(fā)生了

      多矩形碰撞。其中多圓形碰撞也是同樣的道理,只是包裹的圖形區(qū)域是圓形罷了。

      不過(guò)仔細(xì)思考多矩形碰撞同樣會(huì)有誤差,雖然這種誤差十分小。

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)


  像素級(jí)別的碰撞檢測(cè)

       像素級(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ā)中是盡量避免使用的!

   規(guī)則圖形碰撞檢測(cè)2

         對(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ì)明白了。


Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

         小圓有個(gè)運(yùn)動(dòng)軌跡,軌跡的線如果和他對(duì)著的正方形的相對(duì)某一象限的邊有焦點(diǎn),那么

      就能碰撞,邊就是那一個(gè)象限的邊(還要把圓半徑算進(jìn)去),具體代碼就不實(shí)現(xiàn)了,讀者可

      自己嘗試著去實(shí)現(xiàn)。    

  不規(guī)則圖形碰撞檢測(cè)

     對(duì)于矩形碰撞,很多人都知道。但面對(duì)多邊形圖形,大多數(shù)采用多矩形覆蓋的方式。

       SAT 一種可以快速檢測(cè)不規(guī)則的凸多邊形是否碰撞的算法給出兩個(gè)凸多邊形體,

    如果我們能找到一個(gè)軸線,使兩物體在此軸線上的投影不重疊,則這兩個(gè)物體之間沒(méi)有

    發(fā)生碰撞,這個(gè)軸線叫做Separating Axis(紅色軸線)。

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

       對(duì)于2D來(lái)說(shuō),紅色線就是垂直與多邊形邊的軸。

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

      因此,如果我們要檢查兩多邊形是否碰撞,就去檢查兩多邊形在每個(gè)所有可能的軸上的投影

   是否重疊。

Java簡(jiǎn)單游戲開(kāi)發(fā)之碰撞檢測(cè)

/// 檢測(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;//表示知道未碰撞
}



向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI