在我的碰撞检测系统上使用EaselJS进行迷你游戏开发时遇到问题,我需要别人的帮助。当英雄(一个圆形位图)与一个对象碰撞,并且第一个对象后面还有另一个对象时,即使第二个碰撞被阻止,英雄也会与两个对象碰撞,就会发生此问题。这是图片说明:



问题的原因确实很简单,即使问题本身并非如此:

该碰撞检测系统基于圆的 future 位置(而不是其实际位置),然后,如果圆的下一个位置与矩形相交,它将反弹。问题是,如果将来的位置与两个矩形相交,则该圆将在两个矩形中反弹-即使实际的圆运动被另一个矩形阻止并且无法到达第二个矩形。

更新:请注意,仅由于由于rect创建顺序而按住向上箭头时才会发生此问题。

这是相关的JavaScript代码:

                rects.forEach(function (rect) { // Affect all rects
                    // Collision detection:
                    // (This MUST BE after every change in xvel/yvel)

                    // Next circle position calculation:
                    var nextposx = circle.x + event.delta / 1000 * xvel * 20,
                        nextposy = circle.y + event.delta / 1000 * yvel * 20;

                    // Collision between objects (Rect and Circle):
                    if (nextposy + height(circle) > rect.y &&
                        nextposx + width(circle) > rect.x &&
                        nextposx < rect.x + rect.width &&
                        nextposy < rect.y + rect.height) {
                        if (circle.y + height(circle) < rect.y) {
                            cls("top");
                        }
                        if (circle.x + width(circle) < rect.x) {
                            cls("left");
                        }
                        if (circle.x > rect.x + rect.width) {
                            cls("right");
                        }
                        if (circle.y > rect.y + rect.height) {
                            cls("bottom");
                        }
                    }

                    // Stage collision:
                    if (nextposy < 0) { // Collided with TOP of stage. Trust me.
                        cls("bottom"); // Inverted collision side is proposital!
                    }
                    if (nextposx < 0) {
                        cls("right");
                    }
                    if (nextposx + width(circle) > stage.canvas.width) {
                        cls("left");
                    }
                    if (nextposy + height(circle) > stage.canvas.height) {
                        cls("top");
                    }
                });

JSFiddle

最佳答案

您必须分别处理水平和垂直碰撞。

我对您的JS fiddle 做了一些小的更改:http://jsfiddle.net/Kf6cv/1/
它现在应该可以正常工作,我所做的是将您的一张支票分成两张:

if (nextposy + height(circle) > rect.y &&
    circle.x + width(circle) > rect.x &&
    circle.x < rect.x + rect.width &&
    nextposy < rect.y + rect.height) {
    if (circle.y + height(circle) < rect.y) {
       cls("top");
    }
    if (circle.y > rect.y + rect.height) {
        cls("bottom");
    }
}

if (nextposx + width(circle) > rect.x &&
    nextposx < rect.x + rect.width &&
    circle.y + height(circle) > rect.y &&
    circle.y < rect.y + rect.height) {
    if (circle.x + width(circle) < rect.x) {
        cls("left");
    }
    if (circle.x > rect.x + rect.width) {
        cls("right");
    }
}

这样做的原因是,如果立即检查两个方向,即使它可能向一个方向移动,也将防止两个方向的移动(或使其反弹)(如图片中的红色数字)。通常,水平/垂直检查的顺序无关紧要,通常仅在“英雄”以100%的边对边方法接近另一个对象时才重要。但是您可以做的是先检查较高方向的方向,因此| velX | > | velY |然后您首先检查水平碰撞。

我还要说,检查后直接应用新位置比较安全,现在它先进行两次独立检查,然后应用两个方向的移动-我不确定,但是我可以想象这可能导致稍后一些问题。

07-24 09:50