使用JQuery检测两个旋转的div是否发生碰撞

7
我希望能够检测两个旋转的div是否发生碰撞。如果它们没有旋转,我知道如何做到这一点,但是当它们实际上旋转时,我不知道该怎么办。
我尝试过一些碰撞插件,例如jQuery Collision (http://sourceforge.net/projects/jquerycollision/),但当div被旋转时,它们并没有起作用。
我使用CSS的transform属性来旋转div。

为什么不使用像Famo.us这样的东西来处理物理效果呢?我相信他们目前只支持圆形碰撞,但是https://github.com/DrClick/FamousBird使用矩形碰撞。请看源代码,Luke。 - Siddharth
1
FamousBird只处理矩形和圆形的相交问题。由于您可能需要自己实现此功能,因此您会发现此答案非常有帮助。您只需要进行一些加法和乘法即可。 - Julian
也许这个可以帮到你:http://shin.cl/pixelperfect/ - Alex
1
一些之前的回答:https://dev59.com/mWgu5IYBdhLWcg3w8bdshttps://dev59.com/HnE95IYBdhLWcg3wI6ft - user3822146
3个回答

5

虽然不是100%准确,但对于大多数情况都是有效的。我使用了这里的算法:

function isUndefined(a) {
    return a === undefined;
}

/**
 * Helper function to determine whether there is an intersection between the two polygons described
 * by the lists of vertices. Uses the Separating Axis Theorem
 *
 * @param a an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
 * @param b an array of connected points [{x:, y:}, {x:, y:},...] that form a closed polygon
 * @return true if there is any intersection between the 2 polygons, false otherwise
 */
function doPolygonsIntersect (a, b) {
    var polygons = [a, b];
    var minA, maxA, projected, i, i1, j, minB, maxB;

    for (i = 0; i < polygons.length; i++) {

        // for each polygon, look at each edge of the polygon, and determine if it separates
        // the two shapes
        var polygon = polygons[i];
        for (i1 = 0; i1 < polygon.length; i1++) {

            // grab 2 vertices to create an edge
            var i2 = (i1 + 1) % polygon.length;
            var p1 = polygon[i1];
            var p2 = polygon[i2];

            // find the line perpendicular to this edge
            var normal = { x: p2.y - p1.y, y: p1.x - p2.x };

            minA = maxA = undefined;
            // for each vertex in the first shape, project it onto the line perpendicular to the edge
            // and keep track of the min and max of these values
            for (j = 0; j < a.length; j++) {
                projected = normal.x * a[j].x + normal.y * a[j].y;
                if (isUndefined(minA) || projected < minA) {
                    minA = projected;
                }
                if (isUndefined(maxA) || projected > maxA) {
                    maxA = projected;
                }
            }

            // for each vertex in the second shape, project it onto the line perpendicular to the edge
            // and keep track of the min and max of these values
            minB = maxB = undefined;
            for (j = 0; j < b.length; j++) {
                projected = normal.x * b[j].x + normal.y * b[j].y;
                if (isUndefined(minB) || projected < minB) {
                    minB = projected;
                }
                if (isUndefined(maxB) || projected > maxB) {
                    maxB = projected;
                }
            }

            // if there is no overlap between the projects, the edge we are looking at separates the two
            // polygons, and we know there is no overlap
            if (maxA < minB || maxB < minA) {
                console.log("polygons don't intersect!");
                return false;
            }
        }
    }
    return true;
};

$('#r').click(function() {
    var rota = Math.floor( Math.random() * 100 ),
        rotb = Math.floor( Math.random() * 100 ),
        pointsa = new Array(4),
        pointsb = new Array(4);

    $('#a').css('transform', 'rotateZ(' + rota + 'deg)');
    $('#b').css('transform', 'rotateZ(' + rotb + 'deg)');

    $('#a div').each(function(i) {
        pointsa[i] = {x: parseInt($(this).offset().left), y: parseInt($(this).offset().top)};
    });

    $('#b div').each(function(i) {
        pointsb[i] = {x: parseInt($(this).offset().left), y: parseInt($(this).offset().top)};
    });


    $('#s').val("intersection: " + doPolygonsIntersect(pointsb, pointsa).toString());
});

演示代码

我猜我的脚本并不是最好的方法,它基本上是在0到100度之间随机旋转,获取每个角落(使用div可以用数学方法计算位置,但我不行 :D)的x和y位置,并使用这些坐标运行算法。


是的,分离轴定理是正确的方法。但是你必须获取旋转框的边缘。为了做到这一点,不可避免地需要进行肮脏的数学计算,以获取从CSS解析出的当前旋转角度,并重新计算div的点(因为我认为没有更简单的方法来获取边缘的位置)。这可能有助于重新翻译和解析旋转:http://css-tricks.com/get-value-of-css-rotation-through-javascript/ - jbrosi

-1

我发现了yckartoverlaps.js

我在这里用旋转的div制作了一个fiddle:http://jsfiddle.net/n3M5e/

你可以自己在CSS中更改div的旋转,检测仍然有效。

overlaps.js:

(function ($) {
    $.fn.overlaps = function (obj) {
        var elems = {
            targets: [],
            hits: []
        };
        this.each(function () {
            var bounds = $(this).offset();
            bounds.right = bounds.left + $(this).outerWidth();
            bounds.bottom = bounds.top + $(this).outerHeight();

            var compare = $(obj).offset();
            compare.right = compare.left + $(obj).outerWidth();
            compare.bottom = compare.top + $(obj).outerHeight();

            if (!(compare.right < bounds.left || compare.left > bounds.right || compare.bottom < bounds.top || compare.top > bounds.bottom)) {
                elems.targets.push(this);
                elems.hits.push(obj);
            }
        });

        return elems;
    };
}(jQuery));

希望我有所帮助。

编辑:

感谢 @jbrosi,overlaps.js 与旋转的 div 不太兼容。


它不适用于旋转的框 - 我更改了您Fiddle的起始条件以创建“假位置”:http://jsfiddle.net/jbrosi/D7vfd/ - jbrosi

-1
你正在寻找div碰撞检测。
如果你想触发一个事件,你必须不断地进行测试,但最好的方法是对所有的div运行函数。
示例演示见http://jsfiddle.net/nGRwt/7/
这里是你需要使用的函数。
function collision($div1, $div2) {
      var x1 = $div1.offset().left;
      var y1 = $div1.offset().top;
      var h1 = $div1.outerHeight(true);
      var w1 = $div1.outerWidth(true);
      var b1 = y1 + h1;
      var r1 = x1 + w1;
      var x2 = $div2.offset().left;
      var y2 = $div2.offset().top;
      var h2 = $div2.outerHeight(true);
      var w2 = $div2.outerWidth(true);
      var b2 = y2 + h2;
      var r2 = x2 + w2;

      if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
      return true;
    }

另一个演示

您还可以参考http://jsfiddle.net/98sAG/进行碰撞检测。

使用以下代码:

var overlaps = (function () {
    function getPositions( elem ) {
        var pos, width, height;
        pos = $( elem ).position();
        width = $( elem ).width();
        height = $( elem ).height();
        return [ [ pos.left, pos.left + width ], [ pos.top, pos.top + height ] ];
    }

    function comparePositions( p1, p2 ) {
        var r1, r2;
        r1 = p1[0] < p2[0] ? p1 : p2;
        r2 = p1[0] < p2[0] ? p2 : p1;
        return r1[1] > r2[0] || r1[0] === r2[0];
    }

    return function ( a, b ) {
        var pos1 = getPositions( a ),
            pos2 = getPositions( b );
        return comparePositions( pos1[0], pos2[0] ) && comparePositions( pos1[1], pos2[1] );
    };
})();

希望这能对你有所帮助 :)

可能是因为楼主要求在两个 div 旋转时进行碰撞检测,而你的代码没有实现 - 我没有点踩。 - Sam
但这并不意味着它是错误的或不适当的 :( - Mazzu
1
他确实说过他已经知道如何检测非旋转元素的碰撞。问题是关于旋转/旋转后的元素。 - jjjjjjjjjjjjjjjjjjjj
好的,没问题。我明白了 :) - Mazzu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接