web-dev-qa-db-ja.com

Javascript:衝突検出

誰かがJSで衝突検出がどのように機能するかを理解するのを助けてくれますか?私はjQueryまたはgameQueryを使用できません-既にプロトタイプを使用しているので、非常に単純なものを探しています。完全な解決策を求めるのではなく、正しい方向を示してください。

があるとしましょう:

<div id="ball"></div>
and 
<div id="someobject0"></div>

今、ボールは動いています(任意の方向)。 「Someobject」(0-X)はすでに事前定義されており、20〜60個が次のようにランダムに配置されています。

#someobject {position: absolute; top: RNDpx; left: RNDpx;} 

「someobject(X)」の位置を使用して配列を作成し、「ボール」が動いている間に衝突をテストできます。

for(var c=0; c<objposArray.length; c++){
........ and code to check ball's current position vs all objects one by one....
}

しかし、これは「noob」ソリューションであり、かなり遅いように思えます。もっと良いものはありますか?

45
jack moore

最初に必要なのは、ボールとオブジェクトの衝突があるかどうかを検出する実際の機能です。

パフォーマンスのために、たとえば bounding rectangles などの粗い衝突検出技術を実装するのは素晴らしいことです。衝突が検出された場合、必要に応じてより正確なものを実装して、関数が実行されるようにします。少し速くなりますが、まったく同じループを使用します。

パフォーマンスの向上に役立つもう1つのオプションは、所有しているオブジェクトで前処理を行うことです。たとえば、領域全体を汎用テーブルのようなセルに分割し、特定のセルに含まれる適切なオブジェクトを保存できます。したがって、衝突を検出するには、ボールが占めるセルを検出し、それらのセルからオブジェクトを取得して、衝突検出機能を使用します。

さらに高速化するには、 2d-treequadtree 、または R-tree を実装できます。

29
Li0liQ

これは非常に単純な境界矩形ルーチンです。 abの両方が、xywidthおよびheightプロパティを持つオブジェクトであると想定しています。

function isCollide(a, b) {
    return !(
        ((a.y + a.height) < (b.y)) ||
        (a.y > (b.y + b.height)) ||
        ((a.x + a.width) < b.x) ||
        (a.x > (b.x + b.width))
    );
}

この関数の動作を確認するには、 こちらはコードペンです@ MixerOID によって丁寧に作成されています。

64
Husky

jquery-collision を試すことができます。完全な開示:これを書いてリリースしたばかりです。解決策が見つからなかったので、自分で書きました。

次のことができます。

var hit_list = $("#ball").collision("#someobject0");

「#ball」と重複するすべての「#someobject0」を返します。

22
eruciform

入力としてHTMLElementsを含むjQueryのないバージョン

これは、要素が絶対的、相対的、または変換によって操作された場合でも、ビューポートに表示されている要素の実際の位置をチェックするより優れたアプローチです。

function isCollide(a, b) {
    var aRect = a.getBoundingClientRect();
    var bRect = b.getBoundingClientRect();

    return !(
        ((aRect.top + aRect.height) < (bRect.top)) ||
        (aRect.top > (bRect.top + bRect.height)) ||
        ((aRect.left + aRect.width) < bRect.left) ||
        (aRect.left > (bRect.left + bRect.width))
    );
}
17
Àlex Garcés

「bcmの」答えは、現時点では0票を持っていますが、実際には、あまり評価されていない素晴らしい答えです。古き良きピタゴラスを使用して、オブジェクトが結合された境界円よりも近い場合を検出します。単純な衝突検出では、多くの場合、長方形の衝突検出を使用します。これは、スプライトが長方形になる傾向がある場合に適しています。ボール、小惑星、または極端な角が通常透明である他の形状など、それらが円形(または長方形未満)である場合、この効率的なルーチンが最も正確であることがわかります。

ただし、わかりやすくするために、コードのより完全なバージョンを以下に示します。

function doCollide(x1, y1, w1, x2, y2, w2) {
    var xd = x1 - x2;
    var yd = y1 - y2;
    var wt = w2 + w1;
    return (xd * xd + yd * yd <= wt * wt);
} 

渡すパラメーターは、2つの異なるSpriteオブジェクトのx、y、およびwidthの値です

7
J Sprague

Mozillaにはこれに関する良い記事があり、以下のコードがあります

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

長方形の衝突

if (rect1.x < rect2.x + rect2.width &&
   rect1.x + rect1.width > rect2.x &&
   rect1.y < rect2.y + rect2.height &&
   rect1.height + rect1.y > rect2.y) {
    // collision detected!
}

サークル衝突

if (distance < circle1.radius + circle2.radius) {
    // collision detected!
}
6
B M

これは私が出会った軽量なソリューションです-

function E() { // check collision
            S = X - x;
            D = Y - y;
            F = w + W;
            return (S * S + D * D <= F * F)
        }

大きい変数と小さい変数は2つのオブジェクト(x座標、y座標、およびw幅)です。

ここ から

5
bcm
//Off the cuff, Prototype style. 
//Note, this is not optimal; there should be some basic partitioning and caching going on. 
(function () { 
    var elements = []; 
    Element.register = function (element) { 
        for (var i=0; i<elements.length; i++) { 
            if (elements[i]==element) break; 
        } 
        elements.Push(element); 
        if (arguments.length>1)  
            for (var i=0; i<arguments.length; i++)  
                Element.register(arguments[i]); 
    }; 
    Element.collide = function () { 
        for (var outer=0; outer < elements.length; outer++) { 
            var e1 = Object.extend( 
                $(elements[outer]).positionedOffset(), 
                $(elements[outer]).getDimensions() 
            ); 
            for (var inner=outer; inner<elements.length; innter++) { 
                var e2 = Object.extend( 
                    $(elements[inner]).positionedOffset(), 
                    $(elements[inner]).getDimensions() 
                ); 
                if (     
                    (e1.left+e1.width)>=e2.left && e1.left<=(e2.left+e2.width) && 
                    (e1.top+e1.height)>=e2.top && e1.top<=(e2.top+e2.height) 
                ) { 
                    $(elements[inner]).fire(':collision', {element: $(elements[outer])}); 
                    $(elements[outer]).fire(':collision', {element: $(elements[inner])}); 
                } 
            } 
        } 
    }; 
})(); 

//Usage: 
Element.register(myElementA); 
Element.register(myElementB); 
$(myElementA).observe(':collision', function (ev) { 
    console.log('Damn, '+ev.memo.element+', that hurt!'); 
}); 
//detect collisions every 100ms 
setInterval(Element.collide, 100);
4
Fordi

これは非効率的な簡単な方法ですが、あまり複雑なものを必要としない場合や、オブジェクトがあまりない場合は非常に合理的です。

それ以外の場合、多くの異なるアルゴリズムがありますが、それらのほとんどは実装が非常に複雑です。

たとえば、divide et imperaアプローチを使用して、距離に応じてオブジェクトを階層的にクラスター化し、クラスターのすべてのアイテムを含む境界ボックスをすべてのクラスターに与えることができます。次に、どのクラスターが衝突するかを確認し、衝突/重複していないクラスターに属するオブジェクトのペアのチェックを回避できます。

それ以外の場合は、汎用の空間分割アルゴリズムを理解して、同様の方法でオブジェクトを分割し、無駄なチェックを回避できます。これらの種類のアルゴリズムは、衝突検出を2つのフェーズに分割します。coarseどのオブジェクトが衝突する可能性があるかを見るものと、fine 1つのオブジェクトを効果的にチェックする方法。たとえば、QuadTreewikipedia を使用して簡単な解決策を試すことができます。

Wikipedia page をご覧ください。ヒントが得られます。

3
Jack

hittest.js;2つの透明なpng画像(ピクセル)の衝突を検出します。 デモとダウンロードのリンク

HTMLコード;

<img id="png-object-1" src="images/object1.png" />
<img id="png-object-2" src="images/object2.png" />

初期化関数;

var pngObject1Element = document.getElementById( "png-object-1" );
var pngObject2Element = document.getElementById( "png-object-2" );

var object1HitTest = new HitTest( pngObject1Element );

基本的な使用法;

if( object1HitTest.toObject( pngObject2Element ) ) {
    //Collision detected
}
1
bugra ozden