如何从另一个矩形中排出一个矩形 - Javascript

How to expel a rect from inside another rect - Javascript

我正试图让 rect1rect2 里面搬出去。我试图四处寻找 awsner,但我无法找到满意的 awnser。我可以检测到矩形相交,但我无法排除 rect1,所以它超出了 rect2。你能提供一些代码来帮助我做到这一点吗?到目前为止,我将提供我的检测代码。

代码:

var DoCollision = function(rect1, rect2, objectToMove){
    if (rect1.x + rect1.w > rect2.x &&
        rect1.x < rect2.x + rect2.w &&
        rect1.y + rect1.h > rect2.y &&
        rect1.y < rect2.y + rect2.h){
            // Expel rect1 from rect2 here using objectToMove as the object being expelled (In this case, rect1).
    };
};

感谢您的回复。

我应该告诉你更大的图景。我正在尝试创建一个函数,其中我输入 3 rect 个对象,以测试它们是否发生碰撞,如果是,我希望第三个 rect 对象相应地移动。比如函数参数是rect1rect2rect1,意思是当rect1rect2相交在左边时,我要第三个参数rect1向左移动

一个简单的解决方案:

var DoCollision = function(rect1, rect2, objectToMove){
    if (rect1.x + rect1.w > rect2.x &&
        rect1.x < rect2.x + rect2.w &&
        rect1.y + rect1.h > rect2.y &&
        rect1.y < rect2.y + rect2.h){
            objectToMove.x = Math.max(rect1.x + rect1.w, rect2.x + rect2.w);
            objectToMove.y = Math.max(rect1.y + rect1.h, rect2.y + rect2.h);
    };
};

但请注意,这仅适用于整个数据集中只有两个矩形的情况。如果有很多矩形,移动 rect1 以避免与 rect2 发生碰撞可能会与其他一些矩形发生碰撞。一般来说,将物体移动到最小距离以避免与所有其他物体碰撞的问题非常困难(可能是 NP-hard,尽管我尚未验证这一点)。

编辑:将碰撞物体从碰撞中移开可能最好是在改变移动物体的位置之前检查碰撞是否会发生(即,计算所需的位置,检查它是否会引起碰撞,如果是,则根本不要移动物体)。但是如果一定要事后做,可以把上面的做法泛化一下:

var DoCollision = function(rect1, rect2, objectToMove){
    var intersectInX = rect1.x + rect1.w > rect2.x &&
                       rect1.x < rect2.x + rect2.w;
    var intersectInY = rect1.y + rect1.h > rect2.y &&
                       rect1.y < rect2.y + rect2.h;
    var collide = intersectInX && intersectInY;
    if ( ! collide ) { return; }
    if (intersectInX) {
        var leftmostEdge = Math.min(rect1.x, rect2.x);
        var rightmostEdge = Math.max(rect1.x, rect2.x);
        if (objectToMove.x > leftmostEdge) { // move right rectangle
            objectToMove.x = rightmostEdge;
        } else {                             // move left rectangle
            objectToMove.x = leftmostEdge - objectToMove.w;
        }
    }
    if (intersectInY) {
        var topmostEdge = Math.min(rect1.y, rect2.y);
        var bottommostEdge = Math.max(rect1.y, rect2.y);
        if (objectToMove.y > topmostEdge) { // move bottom rectangle
            objectToMove.y = bottommostEdge;
        } else {                            // move top rectangle
            objectToMove.y = topmostEdge - objectToMove.h;
        }
    }
};

这没有解决您需要决定矩形行为方式的 2 种情况: 1) 如果一个矩形完全包围另一个。它们将分开,但不一定以您想要的方式分开。 2) 如果移动导致与外边界相交。

一种方法是确定在 X 或 Y 方向移动所需的最小量,然后移动该量。这不考虑任何边界矩形:

function doCollision(rect1, rect2, objectToMove){
    if (rect1.x + rect1.w > rect2.x &&
        rect1.x < rect2.x + rect2.w &&
        rect1.y + rect1.h > rect2.y &&
        rect1.y < rect2.y + rect2.h){
            if (objectToMove === rect1) {
                moveOutside(objectToMove, rect2);
            }
            else if (objectToMove === rect2) {
                moveOutside(objectToMove, rect1);
            }
    };
};

function moveOutside(rectToMove, otherRect) {
    // Determine if the overlap is due more to x or to y,
    // then perform the appropriate move

    var moveOverOtherX = rectToMove.x + rectToMove.w - otherRect.x;
    var otherOverMoveX = otherRect.x + otherRect.w - rectToMove.x;

    var moveOverOtherY = rectToMove.y + rectToMove.h - otherRect.y;
    var otherOverMoveY = otherRect.y + otherRect.h - rectToMove.y;

    var minOver = Math.min(moveOverOtherX, otherOverMoveX, moveOverOtherY, otherOverMoveY);

    if (minOver == moveOverOtherX) {
        rectToMove.x = otherRect.x - rectToMove.w;
    }
    else if (minOver == otherOverMoveX) {
        rectToMove.x = otherRect.x + otherRect.w;
    }
    else if (minOver == moveOverOtherY) {
        rectToMove.y = otherRect.y - rectToMove.h;
    }
    else {
        rectToMove.y = otherRect.y + otherRect.h;
    }

    rectToMove.update();
}

a fiddle here中查看。