Укороченная версия
Существует ли шаблон дизайна для распределения этикеток транспортных средств непересекающимся образом, размещая их как можно ближе к транспортному средству, к которому они относятся? Если нет, то является ли какой-либо метод, который я предлагаю, жизнеспособным? Как бы вы реализовали это сами?
Расширенная версия
В игре, которую я пишу, у меня есть вид с высоты птичьего полета моих летательных аппаратов. У меня также есть рядом с каждым из транспортных средств небольшая табличка с ключевыми данными об автомобиле. Это фактический скриншот:
Теперь, когда машины могли летать на разных высотах, их значки могли перекрываться. Однако я бы не хотел, чтобы их ярлыки перекрывали друг друга (или ярлык транспортного средства «А» перекрывал значок транспортного средства «В»).
В настоящее время я могу обнаружить столкновения между спрайтами и просто оттолкнуть поврежденную метку в направлении, противоположном спрайту, перекрывающемуся в противном случае . Это работает в большинстве ситуаций, но когда воздушное пространство переполнено, этикетка может отодвинуться очень далеко от своего транспортного средства, даже если была альтернатива «умнее». Например я получаю:
B - label
A -----------label
C - label
где было бы лучше (= наклейка ближе к автомобилю) получить:
B - label
label - A
C - label
РЕДАКТИРОВАТЬ: Следует также учитывать, что помимо случая перекрытия транспортных средств, могут быть другие конфигурации, в которых метки транспортных средств могут перекрываться (примеры ASCII-искусства показывают, например, три очень близких транспортных средства, в которых метка A
будет перекрывать значок B
и C
).
У меня есть две идеи о том, как улучшить существующую ситуацию, но прежде чем тратить время на их реализацию, я подумал обратиться к сообществу за советом (в конце концов, это кажется «достаточно общей проблемой», что шаблон проектирования для него может существовать).
Для чего это стоит, вот две идеи, о которых я думал:
Слотация пространства метки
В этом сценарии я бы разделил весь экран на «слоты» для надписей. Тогда у каждого транспортного средства всегда будет метка, расположенная в ближайшем пустом (пусто = других спрайтов в этом месте нет).
Спиральный поиск
Начиная с местоположения транспортного средства на экране, я попытался бы разместить метку под увеличивающимися углами, а затем с увеличивающимися радиусами, пока не будет найдено неперекрывающееся местоположение. Что-то по линии:
try 0°, 10px
try 10°, 10px
try 20°, 10px
...
try 350°, 10px
try 0°, 20px
try 10°, 20px
...
источник
Ответы:
По сути, эта проблема похожа на проблему предотвращения столкновений. Да, самолеты могут летать на разных высотах, но их метки находятся на одной и той же «высоте».
Существуют такие алгоритмы, как Unaligned Collision Avoidance , которые будут шагом в правильном направлении для вас. Конечно, для вашей ситуации метки «привязаны» к своим плоскостям, поэтому они имеют ограниченный диапазон движения.
Если вы посмотрите на поведение флокирования, вы захотите реализовать первое «правило» флокирования: отталкивание на короткие расстояния. Однако вместо «поворота» в направлении, удаленном от ближайших соседей, вы будете использовать вектор «вдали» в качестве места размещения для вашей метки.
Например:
Большой черный кружок представляет вашу область влияния, зеленый кружок представляет действительные места для метки, центральная зеленая точка - это плоскость, которую вы рассматриваете в настоящее время, маленькая зеленая точка - это точка на круге, выбранная для размещения метки.
Теперь черные точки могут представлять либо другие метки, либо другие плоскости. Я не уверен, какой из них лучше всего подойдет, вы можете лучше избежать, если бы они были другими лейблами, но я не уверен. Очевидно, что стрелки «силы» - это векторы направления между вашей текущей плоскостью и «объектами влияния». Наконец, на коробке стоит этикетка.
Итак, используя ваш пример выше, я думаю, что это приведет к чему-то вроде:
При использовании этого метода есть несколько ситуаций, для которых вам нужно создать особые случаи, например, три плоскости, выровненные вертикально:
Все три надписи могут переворачиваться справа налево, в зависимости от того, как определены углы надписей. По сути, вам просто нужно следить за углами вокруг круга, где ваши метки могут переключаться, из какого угла они нарисованы: 0, 90, 180, 270.
Я думаю, в конце концов, это выглядело бы неплохо, когда лейблы избегали друг друга. Если это слишком отвлекает, возможно, вы можете округлить до 10 градусов для менее частого движения.
Извините за странные детали, большинство из этих вещей, о которых я думал, когда создавал радиальное меню для своей игры, но я думаю, что в этой «динамической» форме это будет работать довольно хорошо.
источник
Подумав немного, я наконец решил реализовать метод спирального поиска, который я кратко описал в исходном вопросе.
Обоснование состоит в том, что метод Byte56 требует специальной обработки для определенных условий, в то время как поиск по спирали - нет, и он кодирует очень компактным способом . Кроме того, быстрый поиск подчеркивает нахождение ближайшего места к транспортному средству для размещения этикетки, что, по мнению IMO, является основным фактором, делающим карту удобочитаемой.
Однако, пожалуйста, продолжайте высказывать свое мнение, так как он не только полезен, но и очень хорошо написан!
Вот скриншот результата, достигнутого с помощью спирального кода:
А вот код, который, хотя и не является автономным, дает представление о том, насколько проста реализация:
Примечание 1 -
tag.place()
возвращает True, если тег полностью находится в видимой области экрана / радара. Таким образом, эта строка выглядит как «продолжать цикл, если тег находится за пределами радара или перекрывает что-то еще ...»Примечание 2 -
tag.connector.update
это метод, который рисует линию, соединяющую значок самолета с меткой / меткой с текстовой информацией.источник