检测两个div是否过于接近或重叠/碰撞

3
我正在尝试检测两个给定的
是否太近或者重叠/碰撞。我有下面这个CodePen,它试图生成20个随机的
,只有在它们的位置不太接近其他现有的
时才将它们附加到中。这是想法,但它并没有按预期工作,我得到了一些与现有的
位置接近/重叠的
。(如果第一次运行完美,请多次运行以找到问题)。

http://codepen.io/anon/pen/fHLzj

有人能看出错误并指出解决方法吗?


嘿,@op,看起来你正在学习我学习的方式...我在2013年三月做了这件事http://www.lastnoob.com/,去看看吧。 - Muhammad Umer
3个回答

2
这有点难以解释和理解,但是我尝试一下:
通过运行for循环,检查每个div与每个div是否相交。
x,y,h,w
- x是左上角距离左侧的距离。 - y是左上角距离顶部的距离。 - h是div的高度。 - w是div的宽度。
需要考虑的一点是...你不需要真的检查每个div...考虑一下:
假设有10个div...
- 首先,你将检查1号与9号。 - 第二个与第8个。 - ............. - 第八个与第2个。 - 第九个与第1个。 - 不要检查最后一个。
此外,在分配数据之前,为值分配并检查碰撞是个好主意,然后再将它们分配给DOM。 DOM应该只用于呈现最终结果。
我假设你想保留两个相撞的div中的任何一个都不保留。

Preview http://jsfiddle.net/techsin/m4fSf/6/

如预期的那样,代码很庞大。
var
div={},
number=10,
size=20,
m = ele('main');
mw= parseFloat(getComputedStyle(m).getPropertyValue("width"))-size,
mh= parseFloat(getComputedStyle(m).getPropertyValue("height"))-size,
f=true,
nn;    

var i
for (i = 0; i < number; i++) {
    div[i] = {};
    var t = true, newX, newY, nn;
   if (i!=0){ 
       while (t) {

        newX = rand(mw);
        newY = rand(mh);

        for (nn = 0; nn < i; nn++) {
            if (!(((newX > div[nn].x + size+5) || (newY > div[nn].y + size+5)) ||
             ((newX + size+5 < div[nn].x) || (newY + size+5 < div[nn].y)))) {
                    break;
                }
                if (nn == i-1) t = false;
            }}} else {
        newX = rand(mw);
        newY = rand(mh);
            }


console.log(newX);
    div[i].x = newX;
    div[i].y = newY;
}

for (i = 0; i < number; i++) {
render(div[i]);
}


console.log(div);
function render(x){
var d=document.createElement('div');
    d.style.position='absolute';
    d.style.left=(x.x+'px');
    d.style.top=(x.y+'px');
    m.appendChild(d);
}
function rand(x) { return Math.random()*x;} 
function ele(x){return document.getElementById(x);}

这段代码来自我的碰撞网站...我会尝试将其放入上面的代码中,但这是避免碰撞和关闭间隙所需的内容。
if (xpost+30>xx.left && xx.left>xpost && xx.top+30>ypost  && xx.top<ypost+30)  { xspeed = -speed; }
            if (xpost<xx.left+30 && xx.left<xpost && xx.top+30>ypost  && xx.top<ypost+30)  { xspeed = speed; }
            if (ypost+30>xx.top && xx.top>ypost && xx.left+30>xpost  && xx.left<xpost+30)  { yspeed = -speed; }
            if (ypost<xx.top+30 && xx.top<ypost && xx.left+30>xpost  && xx.left<xpost+30)  { yspeed = speed; }

当您检查第9个div是否发生碰撞时,不需要将其与之前的div进行比较。因为如果它们没有与其发生碰撞,那么它也不会与其他任何人发生碰撞。但它可能会与下一个div发生碰撞,而当它没有发生碰撞时,这意味着最后一个div也没有与其他任何人发生碰撞。 - Muhammad Umer
@Muhammad Umer,你能否在codepen.io上发布演示?jsFiddle在这里被封锁了。 - ke3pup
@Muhammad Umer,你的代码只是避免碰撞,对于当前 DIV 的位置与渲染前相邻 DIV 的位置之间是否有足够的间隙(上/左)并不关心。或者我理解代码有误吗? - ke3pup
是的,但要做到这一点,您只需要在那个大的if语句中添加一个数字,就像这样..div[nn].x + size+5 - Muhammad Umer
需要更改那个if语句,因此这并不完整。 - Muhammad Umer
显示剩余3条评论

0

我改变了碰撞逻辑。它通过比较物体之间的距离来检测一个物体是否靠近另一个物体。我还将逻辑包装在 do-while 循环中,这样它将不断尝试找到放置正方形的位置,你将恰好有 20 个正方形。

这个方法可行:

var positions = [];  //stroe positions of appended divs
var divsize = 20; 
var topGap = 40;  // gap from top
var leftGap = 80;  //gap from left

function generateRandomPositionedDiv(){
    for(var c = 0; c < 20; c++){
        var color = '#'+ Math.round(0xffffff * Math.random()).toString(16);

            $newdiv = $('<div/>').css({
                'width':divsize+'px',
                'height':divsize+'px',
                'background-color': color
            }); 



                var posLeft;
                var posTop;
                var checkObj;
                var collide = false;

                posLeft = Math.floor((Math.random() * ($(document).width() - divsize)));//.toFixed();
                posTop = Math.floor((Math.random() * ($(document).height() - divsize)));//.toFixed();
                checkObj = {x: posLeft, y: posTop};

                collide = checkForCollisions(checkObj);

            if(!collide) {

                positions.push({x: posLeft, y: posTop});

                $newdiv.css({
                    'position':'absolute',
                    'left':posLeft+'px',
                    'top':posTop+'px'
                });

                $('body').append($newdiv);
            }

    }
}

/*function getPositions(box) {
  var $box = $(box);
  var pos = $box.position();
  var width = $box.width();
  var height = $box.height();
  return [ [ pos.left, pos.left + width + leftGap ], [ pos.top, pos.top + height + topGap ] ];
}*/


function comparePositions(obj1, obj2) { 
    if(Math.abs(obj1.x - obj2.x) <= (divsize + leftGap) && Math.abs(obj1.y - obj2.y) <= (divsize + topGap)) {
        return true;
    } else {
        return false;
    }
}

function checkForCollisions(posObj){
    for(var i = 0; i < positions.length; i++){
        var match = comparePositions(positions[i], posObj);
        if (match) { 
                //return true if two positions are close or overlapping
                return match;
            }
    }
}

generateRandomPositionedDiv();

#CodePupper,你的代码似乎没有考虑两个DIV之间的LEFT或TOP间隙(var topGap = 40; var leftGap = 80;)。你能否使它仅在它们基于顶部和左侧的现有位置正确分开时放置div? - ke3pup
我猜你的意思是说,任何两个正方形在x轴上不能相距80像素,在y轴上不能相距40像素。我已经修改了我的代码以反映这个变化。如果可以,请告诉我 :) - CodePuppet
我尝试了你的代码 - 在第二/第三次运行时会冻结。 我猜它陷入了一个无尽循环,永远试图找到适当的间隙! - ke3pup
1
你是对的,代码可能会进入无限循环。我已经更新了代码,使其进行20次尝试,而不是试图放置确切的20个正方形。 - CodePuppet

0

第二个链接似乎有点过头了。我认为实现起来不难,所以没有考虑使用外部库。出于学习和保持问题的焦点,我更喜欢不使用外部库。请注意,我有两件事情要考虑,不仅是碰撞检测,还有两个给定DIV之间的间隙,即它们不能重叠,并且它们不能比相邻DIV的特定TOP和LEFT更接近。 - ke3pup
jquerycollision还可以告诉您两个元素之间的间隙以及它们是否发生碰撞,不过这听起来像是您想要解决一个优化问题,即在给定约束条件下布置最佳方式。这些问题最好使用某种人工智能(如遗传算法)来解决。请查看末尾的小演示程序http://www.ai-junkie.com/ga/intro/gat3.html。 - Matthew Lock

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