Мой алгоритм обнаружения столкновений срабатывает еще до того, как объекты коснулись - PullRequest
1 голос
/ 22 ноября 2011

Я написал очень простую демонстрацию обнаружения столкновений: http://jsfiddle.net/colintoh/UzPg2/5/

Как видите, объекты иногда вообще не соединяются, но столкновение происходит. Радиус для шариков составляет 10 пикселей, поэтому алгоритм запускает столкновение всякий раз, когда расстояние между двумя центрами шариков составляет менее 20 пикселей. Я уменьшил его до 18px для лучшего изображения, но пустое столкновение все еще происходит случайно. Я что-то не так делаю?

Ответы [ 2 ]

3 голосов
/ 22 ноября 2011

Похоже, вы не используете правильную формулу для расстояния между двумя точками. См. http://www.purplemath.com/modules/distform.htm для полного объяснения.

Вы делаете это:

this.ballCollide = function(balli) {
    if (Math.abs((this.x) - (balli.x)) < (2*radius - buffer)) {
        if (Math.abs((this.y) - (balli.y)) < (2*radius - buffer)) {
             // Do collision
        }
    }
};

Это квадратная ограничительная рамка, а не круглая. Чтобы получить круглую ограничительную рамку, вы можете сделать что-то вроде этого, основываясь на формуле на указанной веб-странице:

this.ballCollide = function(balli) {
    var deltax = this.x - balli.x;
    var deltay = this.y - balli.y;
    if (Math.sqrt(deltax * deltax + deltay * deltay) < 2 * radius - buffer) {
        // Do collision
    }
};

См. http://jsfiddle.net/UzPg2/14/ для рабочего примера.

Обратите внимание, что идеальный круговой ограничивающий прямоугольник намного медленнее алгоритм, чем аппроксимация квадратного ограничивающего прямоугольника.

Следуя точке Джаррода Роберсона (идеальный круг всегда находится внутри идеального квадрата), вы бы сделали это, по сути, объединив свой исходный код с кодом, который я разместил, вот так (и вы могли бы объединить их оба в один условный переход, если ты хотел):

var deltax = this.x - balli.x;
var deltay = this.y - balli.y;
var dist = 2 * radius - buffer;
if (Math.abs(deltax) < dist && Math.abs(deltay) < dist) {
    if (Math.sqrt(deltax * deltax + deltay * deltay) < dist) {
       // Do collision
    }
}

См. http://jsfiddle.net/UzPg2/21/ для рабочего примера (я оставил buffer, поскольку ваша переменная называется 2, но лично я думаю, что она выглядит лучше со значением 1).

Есть также много других способов оптимизировать это для скорости, если вам нужно, но предложение Джаррода дает вам самый большой немедленный прирост скорости.

1 голос
/ 22 ноября 2011

Вы проверяете только столкновения по двум осям, x и y. Вам нужно использовать теорему Пифагора для обнаружения по всем осям ценой эффективности. Например.

Ваш алгоритм обнаружит столкновение вокруг точки, где находятся эти два шара, поскольку, если вы проведете касательную линию вдоль оси x или y от одного шара, он пройдет через другой шар: http://jsfiddle.net/XpXzW/1/

Здесь вы можете увидеть, где они на самом деле должны сталкиваться: http://jsfiddle.net/wdVmQ/1/

Если вы измените свой алгоритм обнаружения столкновений, чтобы проверить идеальные столкновения (это будет менее эффективно), вы также можете избавиться от буфера:

http://jsfiddle.net/ucxER/

(Используя теорему Пифагора, формула для столкновения:

 Math.sqrt((this.x - balli.x)*(this.x - balli.x) 
   + (this.y - balli.y)*(this.y - balli.y)) < 2*radius

Также то, что прокомментировал Джаррод, очень умно. Вы можете ускорить его, используя такую ​​технику. Поскольку квадратный корень рассчитывается только тогда, когда шары находятся близко друг к другу:

http://jsfiddle.net/bKDXs/

...