html5游戏-包围盒检测算法

矩形包围盒算法:检测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;
                }
            },
原文地址:https://www.cnblogs.com/gongshunkai/p/5818771.html