Flash: ближайшая точка к мувиклипу - PullRequest
3 голосов
/ 05 марта 2010

Мне нужно ограничить точку внутри DisplayObject, предоставленной мне художником.

У меня это работает, но только в тех случаях, когда курсор все еще находится внутри bounds.
Ограниченный объект называется limited.

function onSqMouseMove(event:MouseEvent) {
    if(bounds.hitTestPoint(event.stageX, event.stageY, true)) {
        limited.x = event.stageX;
        limited.y = event.stageY;
    } else {
        /* Find closest point in the Sprite */
    }
}

limited.addEventListener(MouseEvent.MOUSE_DOWN, function(event:MouseEvent) {
    stage.addEventListener(MouseEvent.MOUSE_MOVE, onSqMouseMove);
});

limited.addEventListener(MouseEvent.MOUSE_UP, function(event:MouseEvent) {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, onSqMouseMove);
});

Как мне реализовать другую половину функции? Я знаю, что startDrag Sprite принимает аргументы, где второй является прямоугольником ограничения, но в моем случае bounds - произвольная форма.

Когда объект перетаскивается за границы, я хочу вычислить ближайшую точку от курсора до bounds 'многоугольника.

Просто чтобы заметить, что bounds может иметь «дыры».

Edit:

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

alt text
(источник: liranuna.com )

Ответы [ 5 ]

1 голос
/ 09 марта 2010

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

На ум приходят два метода:

  1. при загрузке уровня, вычислите его в массив n-й точности (например, 5x5 пикселей), скопируйте часть фона и затем проверьте, содержит ли он прозрачность (возможно, getColorBoundsRect( 0xff000000, 0, false );?). обратите внимание, что в массиве содержатся ребра, затем вы можете проверить эту сетку относительно положения мыши, чтобы определить, где находится наиболее вероятный ближайший ребро (любой квадрат, затем два, затем три и т. д.). если вам нужна большая точность, тогда вы можете попробовать какие-то вычисления, если вы знаете, какие из них с наибольшей вероятностью будут содержать ближайший пиксель. Это не будет очень точным и потребует некоторых вычислений в начале, но оно должно быть быстрым для запуска.

  2. если у вас есть круговой спрайт обнаружения попаданий, который вы прикрепляете к позиции курсора, то вы можете развернуть / сжать его и найти точку попадания. начиная с ширины: 0, высоты: 0, когда он соприкасается с фоном, когда он перемещается по краю, расширяйте его на разумную величину (например, 5 пикселей) на цикл до тех пор, пока он не достигнет максимума. затем вы можете отследить эту точку (как показано на странице Grant Skinners как опубликовано viatropos), если область столкновения слишком велика, ваш курсор перемещается ближе к точке столкновения и может уменьшаться на величину до тех пор, пока размер столкновения снова не станет разумным , это немного интенсивно на процессоре, но его всего несколько тестов на фрейм, так же как 30 отскакивающих шариков, это не должно быть слишком сложно в этом.

надеюсь, это даст вам некоторые идеи!

1 голос
/ 10 марта 2010

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

1 голос
/ 08 марта 2010

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

Как насчет этого для начала:

Учитывая, что ваш DisplayObject имеет сплошной цвет, но произвольную форму, это было бы действительно легко по уроку Дуга Маккуна. Дай мне знать, если это приблизит тебя.

Best, Lance

0 голосов
/ 19 августа 2011

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

  • приведение луча от курсора к центру [мувиклип / спрайт]
  • получить расстояние, где оно сталкивается с [movieclip / sprite]
  • получить левую и правую нормали линии от мыши до центральной точки
  • переместить центральную точку вдоль одной нормальной
  • recast ray для новой точки
  • получить расстояние, где он сталкивается с [мувиклип / спрайт]
  • если расстояние больше, чем предыдущее расстояние, переместите центральную точку на противоположную нормаль
  • повторяйте, пока не найдете минимальное расстояние

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

Быстрый гугл дал мне следующие ресурсы, если вы попробуете описанное выше (что, я думаю, я мог бы сделать, если не могу найти альтернативу)

Пример того, чего можно достичь, если у вас была точка на внутренней стороне фигуры и вы нашли ближайшую точку на поверхности (ведущую в большинстве случаев к нормали в этой точке), это на бойдах http://www.red3d.com/cwr/steer/Containment.html

Вы нашли решение для этого?

0 голосов
/ 12 марта 2010

Существует несколько алгоритмических методов, которые могут хорошо работать в зависимости от вашей ситуации:

  1. Предварительно обработайте иллюстрацию и отметьте точки каждые 20 пикселей или около того. Это должно уменьшить количество дистанционных тестов, которые вам нужно выполнить. Если объект перетаскивания находится за пределами границ, определите ближайшую контрольную точку. Определите, какая из двух соседних контрольных точек находится ближе всего к объекту перетаскивания. Выберите точку между ними на основе отношения расстояния (если они почти равноудалены, это будет означать, что ближайшая точка находится почти на полпути). Как то так: Point.interpolate(closestRef, nextClosestRef, factor). Недостатки этого метода заключаются в том, что он не будет точным на 100%, поскольку области между контрольными точками будут уменьшены до прямых линий (что может повлиять на расположение контрольных точек). Другими словами, если у вашего ограничивающего искусства много сложных ребер, этот метод не годится, если, с другой стороны, у него много прямых линий, он великолепен.
  2. На абстрактном уровне ваша проблема называется " проблема ближайшего соседа". Поиск в Google может привести к некоторому эффективному решению.
  3. Подобно тому, что описано выше, добавьте круговой спрайт обнаружения удара в позицию курсора. Однако вместо того, чтобы увеличивать радиус на 5 пикселей каждый раз, удваивайте его каждый раз, пока он не пересечет ограничивающую форму. Затем выполните бинарный поиск, используя последние две длины радиуса, используемые в качестве нижней и верхней границ. Это даст вам расстояние до ближайшей точки на ограничивающей фигуре. Перевести это в реальную точку немного сложнее, но не невозможно. Вам просто нужен вторичный частичный круг (не знаю точно, как это называется) прикрепленный спрайт Hitdetect. Отрегулируйте длину дуги в аналогичном двоичном поиске, чтобы определить угол. Теперь сделайте Point.polar(radius, angle).add(cursorPosition), чтобы получить фактическую точку на границе фигуры.
  4. Я почти уверен, что есть способ сделать 3, но с использованием прямоугольников, которые имеют собственную реализацию во Flash Platform. Хотя я не совсем уверен, но стоит подумать.

Просто для справки, всегда полезно сначала изучить API и посмотреть, есть ли уже библиотека, которая делает то, что вам нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...