AS3 - Как мне найти, где линия сталкивается с прямоугольным объектом? - PullRequest
1 голос
/ 09 ноября 2011

Я разрабатываю игру с Flixel в качестве основы, и часть того, что мне нужно, это способ проверки столкновений вдоль линии (в частности, от линии A до точки B).Лучший способ объяснить это - у меня есть лазерный луч, стреляющий с одного корабля на другой объект (или в точку в пространстве, если ничто не перекрывает линию).Я хочу, чтобы линия доходила только до тех пор, пока не достигнет объекта.Как я могу определить математически / программно, где вдоль линии линия сталкивается с объектом?

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

Редактирование: Перед проверкой объекта на столкновение с самой линией я сначала удалил бы любые объекты, не входящие в ограничивающий прямоугольник линии.- определяется x самой левой точки, y самой верхней точки, x самой правой точки и y самой нижней точки.Это ограничит проверки на столкновение строк несколькими объектами.

Снова отредактируйте: кажется, мой вопрос все еще не до конца ясен, извините.Некоторые из решений, вероятно, сработают, но я ищу простое, предпочтительно математическое решение.И когда я говорю «прямоугольник», я имею в виду тот, чьи стороны зафиксированы по осям x и y, а не вращающийся прямоугольник.Таким образом, линия не является прямоугольником шириной 0, если она не находится под углом 90 или -90 градусов (при условии, что 0 градусов указывают справа от экрана).

Вот визуальное представление того, что я пытаюсь найти:Line Collision Detection

Ответы [ 4 ]

6 голосов
/ 09 ноября 2011

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

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

typedef struct {
    GLfloat A;
    GLfloat B;
    GLfloat C;
} Line;

static inline Line LineMakeFromCoords(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) {
    return (Line) {y2-y1, x1-x2, (y2-y1)*x1+(x1-x2)*y1};
}

static inline Line LineMakeFromSegment(Segment segment) {
    return LineMakeFromCoords(segment.P1.x,segment.P1.y,segment.P2.x,segment.P2.y);
}

Затем проверьте, пересекаются ли они

static inline Point2D IntersectLines(Line line1, Line line2) {
    GLfloat det = line1.A*line2.B - line2.A*line1.B;
     if(det == 0){
    //Lines are parallel
            return (Point2D) {0.0, 0.0};  // FIXME should return nil
     }else{
            return (Point2D) {(line2.B*line1.C - line1.B*line2.C)/det, (line1.A*line2.C - line2.A*line1.C)/det};
     }  
}

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

Математика - все в Википедии, проверьте там, если вам нужно большеinfo.

Редактировать:

Дополнение для последующего комментария:

То же, что и раньше, проверять ваш сегмент на столкновение со всеми четырьмя сегментамипрямоугольник, вы получите один из 3 случаев:

  1. На экране нет точки столкновения / столкновения (помните, что тесты столкновения направлены против линий, а не сегментов линий, и линии всегда будут пересекаться, если они не параллельны), насмешкаПропал игрок: -)
  2. Одно столкновение, нарисуйте / сделайте все, что вы хотите, сегмент, который вы запрашиваете, будет AC (точка столкновения C)
  3. Два столкновения, проверьтеразмер каждого результирующего сегмента (A-C1) и (A-C2), используя что-то вроде приведенного ниже кода, и оставьте один с самым коротким размером.

    static inline float SegmentSizeFromPoints(Vertice3D P1, Vertice3D P2) {
         return sqrtf(powf((P1.x - P2.x),2.0) + pow((P1.y - P2.y),2.0));
    }
    

Хитрый битпри работе со столкновениями выясняется, как минимизировать количество тестов, которые вы должны выполнить.

1 голос
/ 11 ноября 2011
  1. Найти формулу для строки y = ((y2 - y1)/(x2 - x1)) * (x - x1) + y1
  2. Найти ограничивающие рамки для ваших спрайтов
  3. Для ограничивающей рамки каждого спрайта:
  4. Для каждого углатекущая ограничивающая рамка:
  5. Введите значение x координаты угла в формулу линии (из 1) и вычтите значение y координаты из результата
  6. Запишите знак из расчетав 5
  7. Если все 4 знака равны, то столкновения не будет / не произойдет.Если какой-либо знак отличается, то возможно столкновение, выполните дополнительные проверки.
0 голосов
/ 09 ноября 2011

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

Я нашел ссылку, которая объясняет это в сжатой форме, здесь.

0 голосов
/ 09 ноября 2011

У меня нет математических способностей, но я думаю, что вы могли бы сделать что-то вроде этого:

  1. Измерьте расстояние от центра блока и лазерного луча.
  2. Измерьтерасстояние между центром блока и краем блока под заданным углом (была бы формула для этого, я просто не знаю, что это).

Вычесть результат из точки1 из результата пункта 2.

Хорошо, что если точка 1 больше точки 2, вы знаете, что столкновения еще не было.

В качестве альтернативы используйте box2d , и просто используйте b2ContactPoint

...