矩形包围盒算法:检测2个矩形是否重叠,在这样情况下要判断2个矩形是否碰撞只需要比较两个矩形顶点的坐标即可。假设矩形A用(x1,y1)表示左上角,(x2,y2)表示右下角,矩形B用(x3,y3)表示左上角,(x4,y4)表示右下角,则满足下列条件则表示没有碰撞,反之则碰撞。
没碰撞:x1>x4或者x2<x3。
没碰撞:y1>y4或者y2<y3
var ABBox = function(tBox1,tBox2){ var x1 = tBox1.x, y1 = tBox1.y, x2 = tBox1.x + tBox1.w, y2 = tBox1.y + tBox1.h, x3 = tBox2.x, y3 = tBox2.y, x4 = tBox2.x + tBox2.w, y4 = tBox2.y + tBox2.h; if(x1>x4||x2<x3)return false; if(y1>y4||y2<y3)return false; return true; };
圆形包围盒算法:检测圆形的碰撞比较容易,假设圆A的坐标(x1,y1),半径是r1,圆B的坐标(x2,y2),半径是r2,则如果满足不等式(y2-y1)2+(x2-x1)2<=(r1+r2)2则表示两个圆发生了碰撞,其实就是圆心之间的距离小于两个圆的半径之和即可,由于计算距离需要用到开方运算,效率较低,所以直接比较距离的平方。
var RBBox = function(tBox){ var dx = x-tBox.x, dy = y-tBox.y, dr = r+tBox.r; return dx*dx+dy*dy<dr*dr; };
凸多边形包围盒算法:对于2个多边形来说,检测它们是否相交,我们所要做的是计算两个多边形的每条边在分离轴上的投影的距离。找出每条边形成的向量在轴上投影的最大值和最小值,这样在分离轴上的每个多边形就分别以这两个值形成线段,最后比较这两个线段是否重叠就可以判断这两个多边形是否相交了。
所以在做检测的时候只需要按照以下步骤进行即可。
(1) 产生所有的分离轴,选取一条测试。
(2) 计算图形在该分离轴上的投影。
(3) 检测投影是否相交,如果相交则选取下一条,重复步骤2和步骤3,如果不相交则返回不相交。
(4) 所有分离轴检测完毕,返回相交。
//x,y是多边形中心坐标,pArr是一个顶点数组,点的坐标采用相对中心点坐标,按顺时针存放各顶点 init:function(x,y,pArr) { this.pArr = pArr; this._super(x,y); }, //转换所有顶点坐标到绝对坐标系中 mapToWorld:function() { var p = []; for(var i=0,len = this.pArr.length;i<len-1;i+=2) { p.push(this.pArr[i]+this.x,this.pArr[i+1]+this.y); } return p; }, collided:function(tBox) { var p1 = this.mapToWorld(), p2 = tBox.mapToWorld(); return MathUtil.isCollide(p1,p2); },
//判断两个多边形是否相交碰撞,p1,p2用于保存多边形点的数组 isCollide:function(p1,p2){ //定义法向量 var e = {"x":0,"y":0}; var p = p1, idx=0, len1=p1.length, len2=p2.length; for(var i=0,len = len1+len2;i<len-1;i+=2){ idx = i; //计算两个多边形每条边 if(i>len1){ p=p2; idx=(i-len1); } if(i==p.length-2){ px=p[0]-p[idx]; py=p[1]-p[idx+1]; } else{ px = p[idx+2]-p[idx], py = p[idx+3]-p[idx+1]; } //得到边的法向量 e.x = -py; e.y = px; //计算两个多边形在法向量上的投影 var pp1 = this.calcProj(e,p1); var pp2 = this.calcProj(e,p2); //计算两个线段在法向量上距离,如果大于0则可以退出,表示无相交 if(this.segDist(pp1[0],pp1[1],pp2[0],pp2[1])>0){ return false; } } return true; }
//计算同一个轴上线段的距离s1(min1,max1),s2(min2,max2),如果距离小于0则表示两线段有相交; segDist:function(min1,max1,min2,max2){ if(min1<min2){ return min2-max1; } else{ return min1-max2; } },