碰撞检测

  目录

图形或dom元素碰撞检测

碰撞检测

碰撞检测在游戏开发中是肯定会用到的,检测两个物体是否碰撞,其实非常简单,用一个方法就可以搞定:

1
2
3
4
5
6
7
8
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}

这个方法传入两个对象,返回true就是碰撞了,反之就没碰撞。
再来一个demo:

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
97
98
99
100
101
102
103
104
105
106
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>collision</title>
</head>
<style>
.wrap {
position: relative;
width: 700px;
height: 300px;
border: 1px solid #cccccc;
}
.box1, .box2 {
position: absolute;
width: 100px;
height: 100px;
}
.box1 {
top: 0;
left: 0;
background-color: green;
z-index: 2;
}
.box2 {
top: 100px;
right: 300px;
background-color: brown;
}
</style>
<body>
<div class="wrap">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
<script>
// 工具函数
// 获取style
function getStyle(element, attr) {
var computed;
if(element.currentStyle) {
computed = element.currentStyle;
} else {
computed = window.getComputedStyle(element, false);
}
return computed.getPropertyValue( attr ) || computed[ attr ];
}
// 判断两个物体是否碰撞
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
</script>
<script>
// 获取节点对象
var box1 = document.querySelector('.box1');
var box2 = document.querySelector('.box2');
// box1和box2的信息
box1Obj = {
x: parseInt(getStyle(box1, 'left')),
y: parseInt(getStyle(box1, 'top')),
width: parseInt(getStyle(box1, 'width')),
height: parseInt(getStyle(box1, 'height')),
}
box2Obj = {
x: parseInt(getStyle(box2, 'left')),
y: parseInt(getStyle(box2, 'top')),
width: parseInt(getStyle(box2, 'width')),
height: parseInt(getStyle(box2, 'height')),
}
// 鼠标按下对象
mouseDownObj = {
x: 0,
y: 0
}
// 给box1添加拖拽事件
box1.onmousedown = function(evt) {
mouseDownObj.x = evt.pageX;
mouseDownObj.y = evt.pageY;
box1.onmousemove = function(evt) {
box1.style.left = box1Obj.x + evt.pageX - mouseDownObj.x + 'px';
box1.style.top = box1Obj.y + evt.pageY - mouseDownObj.y + 'px';
var currentBox1Obj = {
x: parseInt(getStyle(box1, 'left')),
y: parseInt(getStyle(box1, 'top')),
width: box1Obj.width,
height: box1Obj.height
}
var bCollision = haveIntersection(currentBox1Obj, box2Obj);
console.log(bCollision);
}
}
document.onmouseup = function(evt) {
box1.onmousemove = Function.prototype;
box1Obj.x = parseInt(getStyle(box1, 'left'));
box1Obj.y = parseInt(getStyle(box1, 'top'));
}
</script>
</html>

以下内容2024.2.6添加

判断点是否在长方形内

需求不复杂可使用

1
2
3
4
5
6
7
8
9
10
11
12
const queryPtInPolygon_ = function(point, polygon) {
let flag = true;
if(
point.x < polygon[0].x ||
point.x > polygon[1].x ||
point.y < polygon[0].y ||
point.y > polygon[2].y
) {
flag = false;
}
return flag;
}

判断点是否在不规则图形内

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
const queryPtInPolygon = function(point, polygon) {

//下述代码来源:http://paulbourke.net,进行了部分修改
//基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则
//在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。

var N = polygon.length;
var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
var intersectCount = 0; //cross points count of x
var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
var p1, p2; //neighbour bound vertices
var p = point; //测试点

p1 = polygon[0]; //left vertex
for (var i = 1; i <= N; ++i) { //check all rays
if (p.x == p1.x && p.y == p1.y) {
return boundOrVertex; //p is an vertex
}

p2 = polygon[i % N]; //right vertex
if (p.y < Math.min(p1.y, p2.y) || p.y > Math.max(p1.y, p2.y)) { //ray is outside of our interests
p1 = p2;
continue; //next ray left point
}

if (p.y > Math.min(p1.y, p2.y) && p.y < Math.max(p1.y, p2.y)) { //ray is crossing over by the algorithm (common part of)
if (p.x <= Math.max(p1.x, p2.x)) { //x is before of ray
if (p1.y == p2.y && p.x >= Math.min(p1.x, p2.x)) { //overlies on a horizontal ray
return boundOrVertex;
}

if (p1.x == p2.x) { //ray is vertical
if (p1.x == p.x) { //overlies on a vertical ray
return boundOrVertex;
} else { //before ray
++intersectCount;
}
} else { //cross point on the left side
var xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x; //cross point of x
if (Math.abs(p.x - xinters) < precision) { //overlies on a ray
return boundOrVertex;
}

if (p.x < xinters) { //before ray
++intersectCount;
}
}
}
} else { //special case when ray is crossing through the vertex
if (p.y == p2.y && p.x <= p2.x) { //p crossing over p2
var p3 = polygon[(i + 1) % N]; //next vertex
if (p.y >= Math.min(p1.y, p3.y) && p.y <= Math.max(p1.y, p3.y)) { //p.y lies between p1.y & p3.y
++intersectCount;
} else {
intersectCount += 2;
}
}
}
p1 = p2; //next ray left point
}

if (intersectCount % 2 == 0) { //偶数在多边形外
return false;
} else { //奇数在多边形内
return true;
}
}

判断一个多边形是否完全在另一个多边形内部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export const queryPlgInPlg = function(inPlg, outPlg) {
let flag = true;
for(let i=0, len=inPlg.length; i<len; i++) {
if(!queryPtInPolygon(inPlg[i], outPlg)) {
flag = false;
break ;
}
}
for(let i=0, len=outPlg.length; i<len; i++) {
if(queryPtInPolygon(outPlg[i], inPlg)) {
flag = false;
break ;
}
}
return flag;
}