web-dev-qa-db-ja.com

長方形と円の衝突を検出する

実際、私は次のコードで長方形と円の衝突を検出しようとしています:-

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

これも私のコードの一部です:-

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;

誰かがここで私を助けて何が悪いのか理解できますか?

9
Gurjit

円と直線の衝突を検出することは簡単ではありません(しかし、それほど複雑でもありません)。

@kuroi nekoのソリューションは正しく、コードが取得するのと同じくらい簡単です。

幸い、ヒットテスト関数を使用するために数学理論を完全に理解する必要はありません。

関数の動作の詳細が必要な場合は、円と長方形が衝突しているかどうかをテストするための4つの手順を使用した説明を次に示します。

デモ: http://jsfiddle.net/m1erickson/n6U8D/

まず、円と長方形を定義します

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

ステップ#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);

ステップ#2:距離がhalfCircle + halfRectより大きい場合、それらは離れすぎて衝突できません

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

ステップ#3:距離がhalfRect未満の場合、それらは確実に衝突しています

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

ステップ#4:長方形のコーナーでの衝突をテストします。

  • 長方形の中心から長方形の角までの線を考えてください
  • 次に、その線を円の半径だけ延長します
  • 円の中心がその線上にある場合、それらは正確にその正しい角で衝突しています。

ピタゴラスの公式を使用して、円と長方形の中心間の距離を比較します。

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

完全なコードは次のとおりです。

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));
}
43
markE

それはそれを行う方法です:

1)円の中心に最も近い長方形の角を見つけます
2)円がコーナーに対してどのように配置されているかを確認します

この関数は3番目のパラメーターを取り、「実線」の長方形と単純なアウトラインを区別できるようにします(つまり、完全に長方形の内側にある円の場合を衝突と見なす必要があるかどうか)。

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! */ }

衝突法線ベクトルを計算する2番目の関数があり、長方形で跳ね返る円をアニメーション化できます。一緒にそれらは このフィドル のベースとして機能します

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 };   
}
5
kuroi neko

円が実際には正方形であると想定する衝突検出の近似バージョン。円が十分に小さい場合、ユーザーは違いに気付かないでしょう。

長方形が中心から描かれている場合:

 if(sphere.x + sphere.radius > (rectangle.x - rectangle.width / 2) &&
    sphere.x - sphere.radius < (rectangle.x + rectangle.width / 2) &&
    sphere.y + sphere.radius > (rectangle.y - rectangle.height / 2) &&
    sphere.y - sphere.radius < (rectangle.y + rectangle.height / 2)) 
 {    
    //collided
 }

長方形が左上から描かれている場合:

if(sphere.x + sphere.radius >  rectangle.x &&
   sphere.x - sphere.radius < (rectangle.x + rectangle.width) &&
   sphere.y + sphere.radius >  rectangle.y &&
   sphere.y - sphere.radius < (rectangle.y + rectangle.height)) 
{  
   //collided
}

そしてここに両方の​​バージョンのjsfiddleがあります: https://jsfiddle.net/TappT/z5r21nu0/16/

2
Alexander

選択した回答で問題が発生したことがわかりました。これが私のものです、私はうまくいくと思います:

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));
}
0
thatOneGuy