Вопрос

I'm having issues during a minigame development using EaselJS with my collision detection system and I need someone's help. The issue occurs when the hero (a circle bitmap) collides an object and there's other object behind the first one, the hero collides with both objects, even if the second collision is blocked. Here's an image explanation:

The cause of the problem is really simple, even if the problem itself isn't:

This collision detection system is based on the future position of the circle (and not on its actual position), then if the next position of the circle intersect a rectangle, it will bounce. The problem is that, if the future position intersects two rectangles, the circle will bounce in both rectangles — even if the actual circle movement is blocked by another rectangle and it can't reach the second one.

Update: Note that this problem only occurs when the up arrow is being hold due to the rect creation order.


Here's the relevant javascript code:

                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

Это было полезно?

Решение

You have to treat horizontal and vertical collisions independently.

I've made some minor changes to your JS-fiddle: http://jsfiddle.net/Kf6cv/1/ it should work now, what I did is I split up your one check into two:

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");
    }
}

The reason for this is that if check both directions at once, it will prevent the movement(or make it bounce) for both directions(like the red figure in your picture) - even if it COULD move into one direction. The order of checking horizontal/vertical usually doesn't matter, it usually only matters if your "hero" approaches the other object 100% edge-to-edge. But what you could to is to first check the direction with the higher velocity, so if |velX| > |velY| then you first check for a horizontal collision.

Also I'd say it is safer to apply the new position directly after checking, right now it does two independend checks and then applies the movement of both directions - I'm not to sure about it but I could imagine that this might lead to some issues later.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top