久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

JavaScript實現(xiàn)碰撞檢測(分離軸定理)

 郭恩 2018-12-08

從根本上來講,分離軸定理(以及其他碰撞算法)的用途就是去檢測并判斷兩個圖形之間是否有間隙,。分離軸定理中用到的方法使算法本身顯得十分獨特。

我所聽到過分離軸定理的最好類比方式是這樣的:

假想你拿一個電筒從不同的角度照射到兩個圖形上,,那么會有怎樣的一系列的陰影投射到它們之后的墻壁上呢?

sat_2.jpg

如果你用這個方式從每一個角度上對這兩個圖形進行處理,并都找不到任何的間隙,那么這兩個圖形就一定接觸,。如果你找到了一個間隙,那么這兩個圖形就顯而易見地沒有接觸,。

從編程的角度來講,從每個可能的角度上去檢測會使處理變得十分密集,。不過幸運的是,,由于多邊形的性質(zhì),你只需要檢測其中幾個關(guān)鍵的角度,。

你需要檢測的角度數(shù)量就正是這個多邊形的邊數(shù),。也就是說,你所需檢測的角度最大數(shù)量就是你要檢測碰撞的兩個多邊形邊數(shù)之和,。舉個例子,,兩個五邊形就需要檢測10個角度。

sat_3.jpg

這是一個簡易但比較啰嗦的方法,,以下是基本的步驟:

步驟一:從需要檢測的多邊形中取出一條邊,,并找出它的法向量(垂直于它的向量),這個向量將會是我們的一個“投影軸”,。

sat_4.jpg

步驟二:循環(huán)獲取第一個多邊形的每個點,,并將它們投影到這個軸上。(記錄這個多邊形投影到軸上的最高和最低點)

sat_5.jpg

 

步驟三:對第二個多邊形做同樣的處理,。

sat_6.jpg

 

步驟四:分別得到這兩個多邊形的投影,,并檢測這兩段投影是否重疊。

sat_7.jpg

 

 

如果你發(fā)現(xiàn)了這兩個投影到軸上的“陰影”有間隙,那么這兩個圖形一定沒有相交,。但如果沒有間隙,,那么它們則可能接觸,你需要繼續(xù)檢測直到把兩個多邊形的每條邊都檢測完,。如果你檢測完每條邊后,,都沒有發(fā)現(xiàn)任何間隙,那么它們是相互碰撞的,。

這個算法基本就是如此的,。

順帶提一下,如果你記錄了哪個軸上的投影重疊值最?。ㄒ约爸丿B了多少),,那么你就能用這個值來分開這兩個圖形。

那么如何處理圓呢,?

 

 

在分離軸定理中,,檢測圓與檢測多邊形相比,會有點點奇異,,但仍然是可以實現(xiàn)的,。

最值得注意的是,圓是沒有任何的邊,,所以是沒有明顯的用于投影的軸,。但它有一條“不是很明顯的”的投影軸。這條軸就是途經(jīng)圓心和多邊形上離圓心最近的頂點的直線,。

sat_8.jpg

 

 

在這以后就是按套路遍歷另一個多邊形的每條投影軸,,并檢測是否有投影重疊。

噢,,對了,,萬一你想知道如何把圓投影到軸上,那你只用簡單地把圓心投影上去,,然后加上和減去半徑就能得到投影長度了,。

二、代碼解析

1,、html代碼如下:

1
2
<canvas width="800" height="500" id="mycanvas">Loading...</canvas>
<div id="select-box"></div>

2,、main.js主要是控制位移以及圓圈大小,代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
var SHAPE_SIZE = 80, SHAPE_HANDLE_SIZE = 10;
var CANVAS_WIDTH, CANVAS_HEIGHT;
var renderer;
var shA = null, shB = null;
window.onload = function () {
    var canvasTag = document.getElementById("mycanvas");
    var canvas = canvasTag.getContext("2d");
    CANVAS_WIDTH = canvasTag.width;
    CANVAS_HEIGHT = canvasTag.height;
    renderer = new Renderer(canvas);
    setInterval(function () {
        renderer.loopDraw();
    }, 30);
    MouseEvent.addEvents(canvasTag);
    main();
};
function main () {
    UIUtils.createSelect();
    shA = UIUtils.createShape(150, 250, "shA-select");
    renderer.add(shA);
    shB = UIUtils.createShape(540, 250, "shB-select");
    renderer.add(shB);
}
function getPolygonVertices (edges, r) { 
    var ca = 0, aiv = 360 / edges, ata = Math.PI / 180, list = new Array();
    for (var k = 0; k < edges; k++) {
        var x = Math.cos(ca * ata) * r,
            y = Math.sin(ca * ata) * r;
        list.push(new Vec2(x, y));
        ca += aiv;
    }
    return list;
}

SHAPE_SIZE = 80, SHAPE_HANDLE_SIZE = 10 (SHAPE_SIZE設(shè)置外圓環(huán)大小,,SHAPE_HANDLE_SIZE設(shè)置內(nèi)圓大?。琔IUtils.createShape(150, 250, "shA-select")設(shè)置第一個圓的x軸,、y軸位移,,還有外圓環(huán)選擇的形狀是什么,,UIUtils.createShape(540, 250, "shB-select")設(shè)置第二個圓的x軸、y軸位移,,還有外圓環(huán)選擇的形狀是什么,。

3、SAT.js主要是控制拖動圓點時,,外框的顏色等,,部分代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var SAT = (function () {
    function testCollision (A, B) {
        var res, color = "#333333";
        if (A.type == "polygon" && B.type == "polygon") {
            res = polygonsCollisionTest(A, B);
        } else if (A.type == "circle" && B.type == "circle") {
            res = circlesCollisionTest(A, B);
        } else {
            var c, p;
            if (A.type == "circle") {
                c = A;
                p = B;
            } else {
                c = B;
                p = A;
            }
            res = circlePolygonCollisionTest(c, p);
        }
        if (res) {
            color = "#FF0000";
        }
        A.color = B.color = color;
    }

4、Circle.js是控制第二個圓的外框顏色等,,代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Circle (r) {
    this.objectIndex = Renderer.objectIndex++;
    this.type = "circle";
    this.r = r;
    this.x = 0;
    this.y = 0;
    this.color = "#333333";
}
Circle.prototype = {
    draw : function (c) {
        c.arc(0, 0, this.r, 0, Math.PI * 2);
    },
    getProjection : function (axis) {
        var pro = Vec2.dot(new Vec2(this.x, this.y), axis) / axis.length();
        return {min : pro - this.r, max : pro + this.r};
    }
};

 

5,、Polygon.js是控制第一個圓的外框顏色等,代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
function Polygon (list) {
    this.objectIndex = Renderer.objectIndex++;
    this.type = "polygon";
    this.vertices = list;
    this.x = 0;
    this.y = 0;
    this.color = "#333333";
}
Polygon.prototype = {
    getRootCoordinate : function () {
        var list = this.vertices, res = new Array();
        for (var i = 0, l = list.length; i < l; i++) {
            var coord = list[i];
            res.push(new Vec2(coord.x + this.x, coord.y + this.y));
        }
        return res;
    },
    draw : function (c) {
        var list = this.vertices;
        if (list.length <= 1) {
            return;
        }
        c.moveTo(list[0].x, list[0].y);
        for (var i = 1, l = list.length; i < l; i++) {
            var coord = list[i];
            c.lineTo(coord.x, coord.y);
        }
        c.closePath();
    },
    getSides : function () {
        var list = this.vertices,
            l = list.length,
            res = new Array();
        if (l >= 3) {
            for (var j = 1, pre = list[0]; j < l; j++) {
                var p = list[j];
                res.push(Vec2.substract(p, pre));
                pre = p;
            }
            res.push(Vec2.substract(list[0], list[l - 1]));
        }
        return res;
    },
    getProjection : function (axis) {
        var list = this.getRootCoordinate(), min = null, max = null;
        for (var i = 0, l = list.length; i < l; i++) {
            var p = list[i];
            var pro = Vec2.dot(p, axis) / axis.length();
            if (min === null || pro < min) {
                min = pro;
            }
            if (max === null || pro > max) {
                max = pro;
            }
        }
        return {min : min, max : max};
    },
    getNearestPoint : function (p1) {
        var list = this.getRootCoordinate(), rP = list[0], minDis = Vec2.distance(p1, rP);
        for (var i = 1, l = list.length; i < l; i++) {
            var p2 = list[i], d = Vec2.distance(p1, p2);
            if (d < minDis) {
                minDis = d;
                rP = p2;
            }
        }
        return rP;
    }
};

 

6,、Renderer.js是控制整體外框的屬性,,比如顏色邊框等,代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Renderer.prototype = {
    loopDraw : function () {
        var c = this.canvas;
        c.fillStyle = "#ff0000";
        c.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
         
        for (var i = 0, l = this.displayList.length; i < l; i++) {
            var o = this.displayList[i];
            c.save();
            c.translate(o.x, o.y);
            c.beginPath();
            c.globalAlpha = 0.6;
            c.arc(0, 0, SHAPE_HANDLE_SIZE, 0, Math.PI * 2);
            c.fillStyle = "#0000FF";
            c.fill();
            c.beginPath();
            c.globalAlpha = 1;
            o.draw(c);
            c.strokeStyle = o.color;
            c.lineWidth = 2;
            c.stroke();
            c.restore();
        }
    },
    add : function (o) {
        this.displayList.push(o);
    },
    remove : function (o) {
        for (var i = 0, l = this.displayList.length; i < l; i++) {
            var child = this.displayList[i];
            if (child.objectIndex == o.objectIndex) {
                this.displayList.splice(i, 1);
                break;
            }
        }
    }
};

 

 

三,、文件以及演示截圖

1,、文件截圖

222.gif

2、演示截圖

blob.png

3,、雙擊index.html文件即可運行看效果

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多