检查圆圈与另一个圆圈碰撞的程度

时间:2016-01-08 05:18:55

标签: javascript html5 canvas

再次开始处理我的Agar.io克隆。两个圆之间的基本碰撞检测是容易的(距离<半径=碰撞)。然而,琼脂的碰撞检测有点复杂。它似乎检测到圆A包含圆圈B的多少,但由于它不是开源的,我无法弄清楚它们是如何做到的。我在GitHub上看到了这个Agar clone,但看起来他们采取了更简单的路线并且只是定期进行碰撞检测。

这就是我现在正在做的事情。

collision: function(circle) {
    var xx = circle.x - this.x;
    var yy = circle.y - this.y;
    var distance = Math.sqrt(xx * xx + yy * yy);
    return distance < this.radius + circle.radius;
},

如何检查另一个圈内有多少圆圈?

1 个答案:

答案 0 :(得分:4)

您可以通过添加2个相交圆圈部分的区域来计算2个圆圈之间的交点区域:

enter image description here

  1. 计算圆相交的2个点。
  2. enter image description here

    1. 计算交叉楔形成的中心角。中心角是通过将一个交叉点与圆心点连接到另一个交叉点而形成的。
    2. enter image description here

      1. 计算圆形截面的面积。您可以通过首先计算楔形区域然后减去楔形非弧三角形的面积来计算圆形截面的面积。
      2. enter image description here减去enter image description here等于enter image description here

        1. 对两个圆重复并添加两个剖面区域以获得两个圆的交叉点的总面积。
        2. enter image description here

          示例代码和演示

          &#13;
          &#13;
          var canvas=document.getElementById("canvas");
          var ctx=canvas.getContext("2d");
          var cw=canvas.width;
          var ch=canvas.height;
          function reOffset(){
            var BB=canvas.getBoundingClientRect();
            offsetX=BB.left;
            offsetY=BB.top;        
          }
          var offsetX,offsetY;
          reOffset();
          window.onscroll=function(e){ reOffset(); }
          
          
          // define 2 circles
          var c1={x:100,y:100,r:100};
          var c2={x:200,y:200,r:150};
          
          // get points where 2 circles' perimeters intersect 
          var pts=intersection(c1.x,c1.y,c1.r,c2.x,c2.y,c2.r);
          
          // get the angle formed by one intersection point
          // and the circle's centerpoint
          // and the other intersection point
          var centralAngle1=centralAngle({x:pts.x1,y:pts.y1},{x:c1.x,y:c1.y},{x:pts.x2,y:pts.y2});
          var centralAngle2=centralAngle({x:pts.x1,y:pts.y1},{x:c2.x,y:c2.y},{x:pts.x2,y:pts.y2});
          
          // calculate the area of the two circle sectors
          var sector1area=parseInt(sectorArea(c1.r,centralAngle1));
          var sector2area=parseInt(sectorArea(c2.r,centralAngle2));
          
          draw();
          
          
          function draw(){
            // stroke circles
            ctx.beginPath();
            ctx.arc(c1.x,c1.y,c1.r,0,Math.PI*2);
            ctx.closePath();
            ctx.stroke();
            ctx.beginPath();
            ctx.arc(c2.x,c2.y,c2.r,0,Math.PI*2);
            ctx.closePath();
            ctx.stroke();
            // intersecting chord
            ctx.beginPath();
            ctx.moveTo(pts.x1,pts.y1);
            ctx.lineTo(pts.x2,pts.y2);
            ctx.stroke();
            // intersection points 
            ctx.fillStyle='red';
            ctx.beginPath();
            ctx.arc(pts.x1,pts.y1,5,0,Math.PI*2);
            ctx.closePath();
            ctx.fill();
            ctx.beginPath();
            ctx.arc(pts.x2,pts.y2,5,0,Math.PI*2);
            ctx.closePath();
            ctx.fill();
            ctx.fillStyle='black';
            // sector labels
            ctx.fillText('sector2',100,100);
            ctx.fillText('sector1',135,135);
            // report sector areas
            ctx.fillText(sector2area,100,112);
            ctx.fillText(sector1area+'px',135,147);
            ctx.fillText('px',100,124);
            //
            ctx.fillText('circle#1',c1.x-35,c1.y-35);
            ctx.fillText('circle#2',c2.x,c2.y);
          }
          
          // calc area of circle section
          function sectorArea(radius,radianSweep){
            var PI=Math.PI;
            var PI2=PI*2;
            // area of wedge with specified sweep angle
            var wedgeArea=(PI*radius*radius)*radianSweep/PI2;
            // area of triangle formed by 2 radii & radianSweep 
            // == side angle side method
            var triangleArea=0.50*radius*radius*Math.sin(radianSweep);
            // subtract triangle area from wedge area
            // leaving the sector area
            return(wedgeArea-triangleArea);
          }
          
          // return angle between 3 points
          function centralAngle(p0,p1,p2) {
            var dx1=p1.x-p0.x;
            var dy1=p1.y-p0.y;
            var dx2=p1.x-p2.x;
            var dy2=p1.y-p2.y;
            var dx3=p2.x-p0.x;
            var dy3=p2.y-p0.y;
            var a=dx1*dx1+dy1*dy1;
            var b=dx2*dx2+dy2*dy2;
            var c=dx3*dx3+dy3*dy3;
            return(Math.acos((a+b-c)/Math.sqrt(4*a*b)));
          }
          
          
          function centralAngleX(x1,y1,x2,y2){
            var dx=x2-x1;
            var dy=y2-y1;
            return(Math.abs(Math.atan2(dy,dx)));
          }
          
          function intersection(x0, y0, r0, x1, y1, r1) {
            var a, dx, dy, d, h, rx, ry;
            var x2, y2;
            /* dx and dy are the vertical and horizontal distances between
               * the circle centers.
               */
            dx = x1 - x0;
            dy = y1 - y0;
            /* Determine the straight-line distance between the centers. */
            d = Math.sqrt((dy*dy) + (dx*dx));
            /* Check for solvability. */
            if (d > (r0 + r1)) {
              /* no solution. circles do not intersect. */
              return false;
            }
            if (d < Math.abs(r0 - r1)) {
              /* no solution. one circle is contained in the other */
              return false;
            }
            /* 'point 2' is the point where the line through the circle
               * intersection points crosses the line between the circle
               * centers.  
               */
            /* Determine the distance from point 0 to point 2. */
            a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
            /* Determine the coordinates of point 2. */
            x2 = x0 + (dx * a/d);
            y2 = y0 + (dy * a/d);
            /* Determine the distance from point 2 to either of the
               * intersection points.
               */
            h = Math.sqrt((r0*r0) - (a*a));
            /* Now determine the offsets of the intersection points from
               * point 2.
               */
            rx = -dy * (h/d);
            ry = dx * (h/d);
            /* Determine the absolute intersection points. */
            var xi = x2 + rx;
            var xi_prime = x2 - rx;
            var yi = y2 + ry;
            var yi_prime = y2 - ry;
            return({x1:xi, y1:yi, x2:xi_prime, y2:yi_prime});
          }
          &#13;
          <canvas id="canvas" width=350 height=350></canvas>
          &#13;
          &#13;
          &#13;