1. 程式人生 > >java 實現精確碰撞檢測。

java 實現精確碰撞檢測。

cnmm22 原創。

用我的方法,你可以在java 裡實現精確的斜角矩形,平行四邊形,不規則矩形,不規則多邊形與圓形的碰撞檢測。

我們知道,在java 裡有一個類,x.getRect().intersects(x1.getRect() 可以實現規則矩形的碰撞檢測:

僅使用 getRect().intersects(w.getRect()

僅使用 getRect().intersects(w.getRect()

僅使用 getRect().intersects(w.getRect()

這是無法容忍的“碰撞檢測”。這不是我要的遊戲效果。

在使我的方法後:

較為精確碰撞檢測

較為精確碰撞檢測

較為精確碰撞檢測

cnmm22 原創,轉載請隨意。

實現方法:我們必須把所有的碰撞分為兩類:與圓形和與多邊形。

圓形與圓形解決方案:檢測兩個碰撞物件的圓心距離,跟兩者半徑之和做比較。

我把要使用的方法都封裝好了,以便您直接使用 :

    /**  步驟一、檢測兩個圓心距離 */
public static double getDistance(Point p, double ox, double oy) { double _x = Math.abs(ox - p.x); double _y = Math.abs(oy - p.y); return Math.sqrt(_x * _x + _y * _y); }

每一張圓形的透明 png圓形圖片,我們都有一個尺寸大小,我們按尺寸大小,得到其半徑。

而要碰撞的兩個圓心座標我們是很好得到的,這個相信我不須解釋。

/* 步驟二、檢測兩個圓心距離,與兩者半徑之和做比較,範例程式碼:

/
.

            Point p1 = new Point(x + W / 2, y + H / 2);
            if (Unit.getDistance(p1, w.yx, w.yy) < w.yr) {

.

以上就完成了圓形的碰撞檢測。

多邊形:騷複雜點,。

解決方案:1、描邊,2,檢測邊到點距離。

例如這個圖形:
cnmm22原創

先描出4個定點,這樣,能以這4個點組合成4條線段。在分別檢測每一條線段與物件中心的距離即可。

示例程式碼:
……………………….

img = tk.getImage(Wall.class.getClassLoader().getResource
("images/4/k8.png")); rx1 = 1; rx2 = 14784; w = 168; h = 88; rx3 = 2; x3 = x; y3 = y + 5; w3 = w - 15; h3 = h - 5; px11 = x + 14; px12 = y + 35; px21 = x + 136; px22 = y + 7; px31 = x + 4; px32 = y + 85; px41 = x + 149; px42 = y + 53;

……………………….

px11,px12,是它的第一個點,px21,px22,是它的第二個點,以此類推。x,y是這張向量圖最左上角滴點,不管那個點有沒有畫素,或者是透明,它都是 x, y。這樣通過影象工具,我們很容易得到一組 px1-pxn, px12-pxn2。

示例程式碼:(分別檢測每一條線段與物件中心的距離)

if (Unit.pointToLine(w.px11, w.px12, w.px21, w.px22, x + W / 2, y + H / 2) < 24) {

                stay();

                return true;
            }
            if (Unit.pointToLine(w.px11, w.px12, w.px31, w.px32, x + W / 2, y + H / 2) < 24) {

                stay();

                return true;
            }
            if (Unit.pointToLine(w.px31, w.px32, w.px41, w.px42, x + W / 2, y + H / 2) < 24) {

                stay();

                return true;
            }
            if (Unit.pointToLine(w.px21, w.px22, w.px41, w.px42, x + W / 2, y + H / 2) < 24) {

                stay();

                return true;

其中 x + W / 2, y + H / 2 ,是點座標,24是檢測距離。以上只是範例。

    /**  封裝方法:檢測邊到點距離 */
    static double pointToLine(int x1, int y1, int x2, int y2, int x0, int y0) {
        double space = 0;
        double a, b, c;
        a = lineSpace(x1, y1, x2, y2);// 線段的長度
        b = lineSpace(x1, y1, x0, y0);// (x1,y1)到點的距離
        c = lineSpace(x2, y2, x0, y0);// (x2,y2)到點的距離
        if (c <= 0.000001 || b <= 0.000001) {
            space = 0;
            return space;
        }
        if (a <= 0.000001) {
            space = b;
            return space;
        }
        if (c * c >= a * a + b * b) {
            space = b;
            return space;
        }
        if (b * b >= a * a + c * c) {
            space = c;
            return space;
        }
        double p = (a + b + c) / 2;// 半周長
        double s = Math.sqrt(p * (p - a) * (p - b) * (p - c));// 海倫公式求面積
        space = 2 * s / a;// 返回點到線的距離(利用三角形面積公式求高)
        return space;
    }

無論如何,解決多邊形碰撞檢測,描邊將會是一個相當大工作量的工作,但是一旦使用熟練後,其實也是相當簡便。因為有圖形工具。

cnmm22 原創

cnmm22 原創

這樣就很迅速得到了 px11,px12,px21,px22 ;px31,px32,px41,px42 類似。

以上就完成了不規則矩形的碰撞檢測。

那多邊形怎樣檢測?

多邊形方法類似,多描幾條邊出來,再分辨判斷點到線距離即可。我就不在贅述了。

假設要檢測的物件是一個橢圓又怎嗎辦?

你可以參考這樣的方法:
這裡寫圖片描述

記住,你描的邊越多,精確度越高,工作量越大。

使用我的方法,你可以最大限度提高碰撞檢測的精確程度,並且可以避免畫素級碰撞檢測帶來的巨大效能損耗,若碰撞的物件為多邊形與多邊形碰撞,或多邊形與曲線碰撞,無法使用我的方法檢測,而實際中,這種碰撞很少,這種情況下,可以建立畫素矩陣,一般的做法比如一個200*200畫素的圖片,我們則需要做一個[200]*[200]的陣列,進行約40000次的遍歷,來完成1幀裡滴碰撞檢測,還要考慮到透明度的計算,其效能消耗相當可觀。