简体   繁体   English

检测矩形与圆的碰撞

[英]Detecting collision of rectangle with circle

Actually I am trying to detect thee collision of the Rectangle with the circle in the following piece of code:- 实际上我试图在下面的代码中检测到矩形与圆形的碰撞: -

function checkCollision() {
     //checking of the Collision
     if (ry + rh > cy - radius && rx + rw > cx - radius && rx + rw < cx + radius ) {
          dy = -dy;
     }
}

This is also the part of my code:- 这也是我的代码的一部分: -

var rx = 50; //distance from the x-axis of the Rect. 
var ry = 50; //distance from the y-axis of the Rect.
var rw = 80; //width of the Rect
var rh = 30; //Height of the Rect.

// Distance to moved of the Rect.
var dx = 2;
var dy = 2;

// Center of the circle from the x-axis and y-axis.
var cx = 105;
var cy = 135;
var radius = 16;
var cx1 = 6;
var cy1 = 6;

Can anyone help me out here to figure out what is wrong? 任何人都可以帮助我找出问题所在吗?

Detecting circle-rect collisions is not trivial (but not that complicated either). 检测圆形碰撞不是微不足道的(但也不是那么复杂)。

@kuroi neko's solution is correct and about as simple as the code is going to get. @kuroi neko的解决方案是正确的,就像代码一样简单。

Luckily, you don't need to fully understand the math theory to use the hit-test function. 幸运的是,您不需要完全理解数学理论来使用命中测试功能。

If you do want more details about how the function works, here is a description using 4 steps to test if a circle and a rectangle are colliding: 如果您确实需要有关函数如何工作的更多详细信息,请使用以下4个步骤来测试圆和矩形是否发生碰撞:

Demo: http://jsfiddle.net/m1erickson/n6U8D/ 演示: http//jsfiddle.net/m1erickson/n6U8D/

First, define a circle and a rectangle 首先,定义一个圆和一个矩形

var circle={x:100,y:290,r:10};
var rect={x:100,y:100,w:40,h:100};

Step#1: Find the vertical & horizontal (distX/distY) distances between the circle's center and the rectangle's center 步骤#1:找到圆的中心和矩形中心之间的垂直和水平(distX / distY)距离

    var distX = Math.abs(circle.x - rect.x-rect.w/2);
    var distY = Math.abs(circle.y - rect.y-rect.h/2);

Step#2: If the distance is greater than halfCircle + halfRect, then they are too far apart to be colliding 步骤2:如果距离大于halfCircle + halfRect,那么它们相距太远而不会发生碰撞

    if (distX > (rect.w/2 + circle.r)) { return false; }
    if (distY > (rect.h/2 + circle.r)) { return false; }

Step#3: If the distance is less than halfRect then they are definitely colliding 步骤3:如果距离小于halfRect,那么它们肯定会发生碰撞

    if (distX <= (rect.w/2)) { return true; } 
    if (distY <= (rect.h/2)) { return true; }

Step#4: Test for collision at rect corner. 步骤#4:测试直角处的碰撞。

  • Think of a line from the rect center to any rect corner 想想从直中心到任何矩形角的线
  • Now extend that line by the radius of the circle 现在将该线延伸到圆的半径
  • If the circle's center is on that line they are colliding at exactly that rect corner 如果圆圈的中心位于该线上,则它们恰好在该直角处碰撞

Using Pythagoras formula to compare the distance between circle and rect centers. 使用毕达哥拉斯公式来比较圆和直中心之间的距离。

    var dx=distX-rect.w/2;
    var dy=distY-rect.h/2;
    return (dx*dx+dy*dy<=(circle.r*circle.r));

Heres the full code: 下面是完整的代码:

var circle={x:100,y:290,r:10};
var rect={x:100,y:100,w:40,h:100};

// return true if the rectangle and circle are colliding
function RectCircleColliding(circle,rect){
    var distX = Math.abs(circle.x - rect.x-rect.w/2);
    var distY = Math.abs(circle.y - rect.y-rect.h/2);

    if (distX > (rect.w/2 + circle.r)) { return false; }
    if (distY > (rect.h/2 + circle.r)) { return false; }

    if (distX <= (rect.w/2)) { return true; } 
    if (distY <= (rect.h/2)) { return true; }

    var dx=distX-rect.w/2;
    var dy=distY-rect.h/2;
    return (dx*dx+dy*dy<=(circle.r*circle.r));
}

That's a way to do it: 这是一种方法:

1) find the corner of the rectangle nearest to the circle center 1)找到最接近圆心的矩形角
2) see how the circle is positioned relative to the corner 2)看看圆圈相对于角落的位置

The function takes a third parameter to allow the distinction between a "solid" rectangle and a simple outline (ie whether the case of a circle located entirely inside the rectangle should be considered a collision) 该函数采用第三个参数来区分“实心”矩形和简单轮廓(即,完全位于矩形内的圆的情况是否应视为碰撞)

function collides (rect, circle, collide_inside)
{
    // compute a center-to-center vector
    var half = { x: rect.w/2, y: rect.h/2 };
    var center = {
        x: circle.x - (rect.x+half.x),
        y: circle.y - (rect.y+half.y)};

    // check circle position inside the rectangle quadrant
    var side = {
        x: Math.abs (center.x) - half.x,
        y: Math.abs (center.y) - half.y};
    if (side.x >  circle.r || side.y >  circle.r) // outside
        return false; 
    if (side.x < -circle.r && side.y < -circle.r) // inside
        return collide_inside;
    if (side.x < 0 || side.y < 0) // intersects side or corner
        return true;

    // circle is near the corner
    return side.x*side.x + side.y*side.y  < circle.r*circle.r;
}

var rect = { x:50, y:50, w:80, h:30 };
var circle = { x:105, y:135, r:16 };

if (collides (rect, circle)) { /* bang! */ }

I have a second function that computes a collision normal vector, to allow animating an circle bouncing off rectangles. 我有第二个函数来计算碰撞法线向量,以允许动画一个圆形弹跳矩形。 Together they serve as a base for this fiddle 它们共同作为这个小提琴的基础

function bounces (rect, circle)
{
    // compute a center-to-center vector
    var half = { x: rect.w/2, y: rect.h/2 };
    var center = {
        x: circle.x - (rect.x+half.x),
        y: circle.y - (rect.y+half.y)};

    // check circle position inside the rectangle quadrant
    var side = {
        x: Math.abs (center.x) - half.x,
        y: Math.abs (center.y) - half.y};
    if (side.x >  circle.r || side.y >  circle.r) // outside
        return { bounce: false }; 
    if (side.x < -circle.r && side.y < -circle.r) // inside
        return { bounce: false }; 
    if (side.x < 0 || side.y < 0) // intersects side or corner
    {
        var dx = 0, dy = 0;
        if (Math.abs (side.x) < circle.r && side.y < 0)
        {
            dx = center.x*side.x < 0 ? -1 : 1;
        }
        else if (Math.abs (side.y) < circle.r && side.x < 0)
        {
            dy = center.y*side.y < 0 ? -1 : 1;
        }

        return { bounce: true, x:dx, y:dy };
    }
    // circle is near the corner
    bounce = side.x*side.x + side.y*side.y  < circle.r*circle.r;
    if (!bounce) return { bounce:false }
    var norm = Math.sqrt (side.x*side.x+side.y*side.y);
    var dx = center.x < 0 ? -1 : 1;
    var dy = center.y < 0 ? -1 : 1;
    return { bounce:true, x: dx*side.x/norm, y: dy*side.y/norm };   
}

I found I came across problems with the selected answer. 我发现我遇到了所选答案的问题。 Here's mine that, I think works well: 这是我的,我认为效果很好:

function collisionCheckCircleRect(circle, rect)
{
    var distx = Math.abs(circle.x - rect.x);
    var disty = Math.abs(circle.y - rect.y);

    if (distx > (rect.width/2 + circle.radius)) { return false; }
    if (disty > (rect.height/2 + circle.radius)) { return false; }

    if (distx <= (rect.width/2)) { return true; } 
    if (disty <= (rect.height/2)) { return true; }

    var hypot = (distx - rect.width/2)*(distx- rect.width/2) +
                         (disty - rect.height/2)*(disty - rect.height/2);

//console.log(hypot <= (circle.radius*circle.radius))
    return (hypot <= (circle.radius*circle.radius));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM