Более быстрый метод, чем Point.distance для расчета столкновения между объектами?

Я разрабатываю игру, в которой у меня много столкновений, и я быстро заметил, что мое узкое место - это линия:

if(Point.distance(_point1, _point2) < collisionDistance){
  //do stuff
}

где _point1 и _point2 - статические переменные, в которых хранятся позиции объектов, которые могут столкнуться, если collisionDistance достаточно низкое.

Знаете ли вы какой-либо более эффективный метод для проверки простого столкновения между двумя кругами?

1 ответ

Решение

Встроенная функция Point.distance очень медленная, поэтому предоставьте свою собственную.

Есть много оптимизаций для расстояния между двумя 2D точками (вы используете круги, поэтому отрегулируйте расстояние столкновения по радиусу круга), и многое зависит от того, как оптимизируют разные компиляторы, но в этом случае мы только говорить о компиляторе asc.

Первый базовый путь - евклидово (пифагорейское) расстояние, которое каждый изучает в триг. учебный класс. Другие методы, такие как метод Таксикаб / Манхэттен, хорошо работают для игр на основе сетки / тайла. Использование быстрого обратного квадратного корня очень быстро, но сложно (невозможно?) Реализовать в прямом ActionScript, но это можно сделать в байт-коде ABC (через ALCHEMY, device, As3c и т. Д.) (Так я и делал действительно сложная проблема на расстоянии... но обычно это не стоит дополнительной работы).

Вот часть теста, который я сделал давным-давно, когда оптимизировал игру. Я немного исправил это и перезапустил некоторые основные методы расстояний, чтобы дать вам преимущество:

Помните, что никогда не тестировали время с помощью проигрывателя DEBUG, всегда используйте версию Release (время выполнения проигрывателя отладки может варьироваться в зависимости от функции / функции относительно проигрывателя release, в 10 раз медленнее в некоторых случаях)...

Air / Flash v19 - релиз плеера:

  • Общее время (мс): 243 (Point.distance)
  • Общее время (мс): 82 (PythaDistance)
  • Общее время (мс): 72 (PythaDistanceNoSqrt)
  • Общее время (мс): 79 (ManhattanTaxiCab)
  • Общее время (мс): 106 (ManhattanTaxiCabNoAbs)

    private var p1:Point = new Point(5, -6);
    private var p2:Point = new Point(-2.5, 3.5);
    private var d1:Number = 0.0;
    private var collisionDistance:Number = 10.0;
    private var collisionDistanceD:Number = collisionDistance * collisionDistance;
    
    private var t1:int = 0;
    private var t2:int = 0;
    private var t3:int = 0;
    
    private function pointDistance(x:int):int {
        t1 = getTimer();
        for (var i:int = 0; i < x; i++) {
            d1 = Point.distance(p1, p2);
        }
        if (d1 < collisionDistance) {
            trace("Collision");
        }
        t2 = getTimer();
        return t2 - t1;
    }
    
    private var dx;
    Number;
    private var dy:Number;
    
    private function PythaDistance(x:int):int {
        t1 = getTimer();
        for (var i:int = 0; i < x; i++) {
            dx = p1.x - p2.x;
            dy = p1.y - p2.y;
            d1 = Math.sqrt(dx * dx + dy * dy);
        }
        if (d1 < collisionDistance) {
            trace("Collision");
        }
        t2 = getTimer();
        return t2 - t1;
    }
    
    private function PythaDistanceNoSqrt(x:int):int {
        t1 = getTimer();
        for (var i:int = 0; i < x; i++) {
            dx = p1.x - p2.x;
            dy = p1.y - p2.y;
            d1 = (dx * dx + dy * dy);
        }
        if ((d1 * d1) < collisionDistanceD) {
            trace("Collision");
        }
        t2 = getTimer();
        d1 = d1 / 2; // show dist. compared to other ways
        return t2 - t1;
    }
    
    private function ManhattanTaxiCab(x:int):int {
        t1 = getTimer();
        for (var i:int = 0; i < x; i++) {
            dx = p1.x - p2.x;
            dy = p1.y - p2.y;
            d1 = Math.abs(dx) + Math.abs(dy);
        }
        if ((d1 * d1) < collisionDistance) {
            trace("Collision");
        }
        t2 = getTimer();
        return t2 - t1;
    }
    
    private function ManhattanTaxiCabNoAbs(x:int):int {
        t1 = getTimer();
        for (var i:int = 0; i < x; i++) {
            dx = p1.x - p2.x;
            if (dx < 0) dx *= -1;
            dy = p1.y - p2.y;
            if (dy < 0) dy *= -1;
            d1 = dx + dy;
        }
        if ((d1 * d1) < collisionDistance) {
            trace("Collision");
        }
        t2 = getTimer();
        return t2 - t1;
    }
    

Существует много способов вычислить расстояние между точками 2D, и многое может зависеть от того, насколько точным вам должно быть расстояние / столкновение. В зависимости от вашей частоты кадров, размера объектов, размера экрана, скорости / движения спрайтов и т. Д.... при большом количестве подделок чисел может происходить без уведомления пользователя (т. Е. Использование целочисленной математики в сравнении с плавающей запятой может иметь огромное значение).

Другие вопросы по тегам