图形碰撞检测 圆与矩形

先建立我们需要的数据模型:

1. 向量:

  1 /**
  2      * 向量类,默认使用正交基
  3      */ 
  4     public class SHVector
  5     {
  6         public var x:Number;
  7         public var y:Number;
  8         public var z:Number;
  9         
 10         /**
 11          * 构造函数
 12          */ 
 13         public function SHVector(x:Number, y:Number, z:Number = 0)
 14         {
 15             this.x = x;
 16             this.y = y;
 17             this.z = z;
 18         }
 19         
 20         /**
 21          * 向量的模
 22          */
 23         public function model():Number
 24         {
 25             return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
 26         }
 27         
 28         /**
 29          * 加法
 30          */ 
 31         public function add(vector:SHVector):SHVector
 32         {
 33             return new SHVector(
 34                 this.x + vector.x,
 35                 this.y + vector.y,
 36                 this.z + vector.z
 37             );
 38         }
 39         
 40         /**
 41          * 减法
 42          */ 
 43         public function sub(vector:SHVector, reverse:Boolean = false):SHVector
 44         {
 45             if (!reverse) {
 46                 return new SHVector(
 47                     this.x - vector.x,
 48                     this.y - vector.y,
 49                     this.z - vector.z
 50                 );
 51             }
 52             else {
 53                 return new SHVector(
 54                     vector.x - this.x,
 55                     vector.y - this.y,
 56                     vector.z - this.z
 57                 );
 58             }
 59         }
 60         
 61         /**
 62          * 点乘(内积)
 63          */
 64         public function dot(vector:SHVector):Number
 65         {
 66             return this.x * vector.x + this.y * vector.y + this.z * vector.z;
 67         }
 68         
 69         /**
 70          * 叉乘(外积)
 71          */ 
 72         public function cross(vector:SHVector):SHVector
 73         {
 74             var resultVector:SHVector = new SHVector(
 75                 this.y * vector.z - this.z * vector.y,
 76                 this.z * vector.x - this.x * vector.z,
 77                 this.x * vector.y - this.y * vector.x
 78             );
 79             
 80             return resultVector;
 81         }
 82         
 83         /**
 84          * 求两条向量的夹角,以弧度为单位
 85          */ 
 86         public function angle(vector:SHVector):Number
 87         {
 88             if (this.model() == 0 ||
 89                 vector.model() == 0)
 90                 return 0;
 91             
 92             return Math.acos(this.dot(vector) / (this.model() * vector.model()));
 93         }
 94         
 95         /**
 96          * 对象信息
 97          */ 
 98         public function toString():String
 99         {
100             return "x:" + this.x + "," +
101                    "y:" + this.y + "," +
102                    "z:" + this.z + "," +
103                    "model:" + this.model();
104         }

2. 圆:

 1 /**
 2      * 圆形类
 3      */ 
 4     public class SHCircle extends RigidityObject
 5     {
 6         public var r:Number;
 7         
 8         public var vector:SHVector;
 9         
10         /**
11          * 构造函数
12          */ 
13         public function SHCircle(x:Number, y:Number, r:Number)
14         {
15             super();
16             
17             this.x = x;
18             this.y = y;
19             this.r = r;
20             
21             this.vector = new SHVector(x, y);
22             
23             this.leftBorder = this.x - this.r;
24             this.rightBorder = this.x + this.r;
25             this.topBorder = this.y - this.r;
26             this.bottomBorder = this.y + this.r;
27             
28             this.draw();
29         }
30         
31         /**
32          * 更新
33          */ 
34         override public function update():void
35         {
36             this.x += this.speedX;
37             this.y += this.speedY;
38             
39             this.vector.x = this.x;
40             this.vector.y = this.y;
41 
42             this.leftBorder = this.x - this.r;
43             this.rightBorder = this.x + this.r;
44             this.topBorder = this.y - this.r;
45             this.bottomBorder = this.y + this.r;
46         }
47         
48         /**
49          * 绘制
50          */ 
51         override protected function draw():void
52         {
53             this.graphics.clear();
54             this.graphics.lineStyle(1, 0x000000);
55             this.graphics.drawCircle(this.x, this.y, this.r);
56         }
57     }

3. 矩形:

 1 /**
 2      * 矩形类
 3      */ 
 4     public class SHRect extends RigidityObject
 5     {
 6         public var vx1:Number;
 7         public var vy1:Number;
 8         public var vx2:Number;
 9         public var vy2:Number;
10         public var vx3:Number;
11         public var vy3:Number;
12         public var vx4:Number;
13         public var vy4:Number;
14         
15         public var vector1:SHVector;
16         public var vector2:SHVector;
17         public var vector3:SHVector;
18         public var vector4:SHVector;
19         
20         /**
21          * 构造函数
22          */ 
23         public function SHRect(vx1:Number, vy1:Number, vx2:Number, vy2:Number, vx3:Number, vy3:Number, vx4:Number, vy4:Number)
24         {
25             super();
26             
27             this.vx1 = vx1;
28             this.vy1 = vy1;
29             this.vx2 = vx2;
30             this.vy2 = vy2;
31             this.vx3 = vx3;
32             this.vy3 = vy3;
33             this.vx4 = vx4;
34             this.vy4 = vy4;
35             
36             this.vector1 = new SHVector(vx1, vy1);
37             this.vector2 = new SHVector(vx2, vy2);
38             this.vector3 = new SHVector(vx3, vy3);
39             this.vector4 = new SHVector(vx4, vy4);
40             
41             this.leftBorder = this.x + vx1;
42             this.rightBorder = this.x + vx2;
43             this.topBorder = this.y + vy1;
44             this.bottomBorder = this.y + vy3;
45             
46             this.draw();
47         }
48         
49         /**
50          * 更新
51          */ 
52         override public function update():void
53         {
54             this.x += this.speedX;
55             this.y += this.speedY;
56             
57             this.vector1.x = this.x + this.vx1;
58             this.vector1.y = this.y + this.vy1;
59             this.vector2.x = this.x + this.vx2;
60             this.vector2.y = this.y + this.vy2;
61             this.vector3.x = this.x + this.vx3;
62             this.vector3.y = this.y + this.vy3;
63             this.vector4.x = this.x + this.vx4;
64             this.vector4.y = this.y + this.vy4;
65             
66             this.leftBorder = this.x + this.vx1;
67             this.rightBorder = this.x + this.vx2;
68             this.topBorder = this.y + this.vy1;
69             this.bottomBorder = this.y + this.vy3;
70         }
71         
72         /**
73          * 绘制
74          */ 
75         override protected function draw():void
76         {
77             this.graphics.clear();
78             this.graphics.lineStyle(1, 0x000000);
79             this.graphics.moveTo(this.vx1, this.vy1);
80             this.graphics.lineTo(this.vx2, this.vy2);
81             this.graphics.lineTo(this.vx3, this.vy3);
82             this.graphics.lineTo(this.vx4, this.vy4);
83             this.graphics.lineTo(this.vx1, this.vy1);
84         }
85     }

 

  为了更清楚的说明矩形和圆的是否相交的情况,先绘制一张图形:

  从图中可以看出圆和矩形位置的三种情况:

  1. 完全不相交:圆形的位置在左上角的两条灰色直线左方,这种情况的判断方式可以通过计算圆心到两条红色直线的距离来得到,图中的黑色箭头实线就代表距离d1和d2,假如我们知道矩形的长是w,宽是h,圆的半径r:

  那么只要满足d1 > r + w / 2 或者 d2 > r + h / 2,圆和矩形就必然不会相交。我们通常会首先使用这个条件进行判断,得出是否肯定不相交的结论。如果这个判断失败,那么圆和矩形有可能相交但也可能不相交(从图中可以清楚看出),我们就需要进行接下来两种情况的判断。

  注:两条红色直线是穿过矩形中心,并分别与矩形的长宽边平行的直线,我们知道矩形中心坐标,和两边的中点坐标就可以得出这两条直线的方程。因为我们知道了矩形4个顶点的坐标,很容易就可以求的矩形中心点和矩形边中点的坐标;

  2. 圆与矩形的边相交:在通过了情况1的验证后,只要满足d1 <= w / 2 或者 d2 <= h / 2,就表明了圆和矩形的某条边一定相交了;

  3. 圆与矩形的顶点相交:如果情况2判断失败,就只剩下和顶点相交的情况了,这个判断很简单,只需要计算圆心到4个顶点的距离是否小于半径r即可;

具体实现:

 1 /**
 2          * 求出点到某条直线的距离
 3          */ 
 4         static public function computeDistanceBetweenPointAndLine(x:Number, y:Number, x1:Number, y1:Number, x2:Number, y2:Number):Number
 5         {
 6             var a:Number = y2 - y1;
 7             var b:Number = x1 - x2;
 8             var c:Number = x2 * y1 - x1 * y2;
 9 
10             return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b);
11         }
12         /**
13          * 检测圆和矩形的相交
14          */ 
15         static public function detectCircleAndRectCollision(circle:SHCircle, rect:SHRect):Boolean
16         {
17             var ABLength:Number = (rect.vector2.sub(rect.vector1)).model(); // 求AB边的长度
18             var DALength:Number = (rect.vector1.sub(rect.vector4)).model(); // 求AD边的长度
19             var halfABLength:Number = ABLength / 2;
20             var halfDALength:Number = DALength / 2;
21             
22             var vectorAB:SHVector = rect.vector2.sub(rect.vector1);
23             var vectorAC:SHVector = rect.vector3.sub(rect.vector1);
24             var vectorAD:SHVector = rect.vector4.sub(rect.vector1);
25             
26             // 矩形中心坐标
27             var rectCenterX:Number = rect.x + vectorAC.x / 2;
28             var rectCenterY:Number = rect.y + vectorAC.y / 2;
29             // AB边的中点坐标
30             var ABCenterX:Number = rect.x + vectorAB.x / 2;
31             var ABCenterY:Number = rect.y + vectorAB.y / 2;
32             // AD边的中点坐标
33             var ADCenterX:Number = rect.x + vectorAD.x / 2;
34             var ADCenterY:Number = rect.y + vectorAD.y / 2;
35             
36             // 圆心到两条直线的距离
37             var d1:Number = CollisionDetectionUtil.computeDistanceBetweenPointAndLine(circle.x, circle.y, rectCenterX, rectCenterY, ADCenterX, ADCenterY);
38             if (d1 > (halfDALength + circle.r))
39                 return false;
40             var d2:Number = CollisionDetectionUtil.computeDistanceBetweenPointAndLine(circle.x, circle.y, rectCenterX, rectCenterY, ABCenterX, ABCenterY);
41             if (d2 > (halfABLength + circle.r))
42                 return false;
43             
44             trace(d1, halfDALength); 
45             trace(d2, halfABLength);
46             
47             // 与矩形某条边相交
48             if ((d1 <= halfDALength) ||
49                 (d2 <= halfABLength))
50                 return true;
51             
52             trace(circle.vector.sub(rect.vector1).model());
53             trace(circle.vector.sub(rect.vector2).model());
54             trace(circle.vector.sub(rect.vector3).model());
55             trace(circle.vector.sub(rect.vector4).model());
56             
57             // 与矩形顶点相交
58             if (circle.vector.sub(rect.vector1).model() <= circle.r ||
59                 circle.vector.sub(rect.vector2).model() <= circle.r ||
60                 circle.vector.sub(rect.vector3).model() <= circle.r ||
61                 circle.vector.sub(rect.vector4).model() <= circle.r)
62                 return true;
63             
64             return false;
65         }

  

原文地址:https://www.cnblogs.com/iRidescent-ZONE/p/4210881.html