Version corta
¿Existe un patrón de diseño para distribuir las etiquetas de los vehículos de manera que no se superpongan, colocándolos lo más cerca posible del vehículo al que se refieren? Si no, ¿es viable alguno de los métodos que sugiero? ¿Cómo implementaría esto usted mismo?
Versión extendida
En el juego que estoy escribiendo tengo una visión panorámica de mis vehículos en el aire. También tengo al lado de cada uno de los vehículos una pequeña etiqueta con datos clave sobre el vehículo. Esta es una captura de pantalla real:
Ahora, dado que los vehículos podrían estar volando a diferentes altitudes, sus íconos podrían superponerse. Sin embargo, me gustaría que sus etiquetas no se superpongan (o que una etiqueta del vehículo 'A' se superponga con el icono del vehículo 'B').
Actualmente, puedo detectar colisiones entre sprites y simplemente elimino la etiqueta ofensiva en una dirección opuesta al sprite superpuesto . Esto funciona en la mayoría de las situaciones, pero cuando el espacio aéreo se llena, la etiqueta puede ser empujada muy lejos de su vehículo, incluso si hubiera una alternativa alternativa "más inteligente". Por ejemplo me sale:
B - label
A -----------label
C - label
donde sería mejor (= etiqueta más cerca del vehículo) obtener:
B - label
label - A
C - label
EDITAR: También debe tenerse en cuenta que, además del caso de los vehículos superpuestos, podría haber otras configuraciones en las que se podrían superponer las etiquetas de los vehículos (los ejemplos de arte ASCII muestran, por ejemplo, tres vehículos muy cercanos en los que la etiqueta de A
se superpondría al icono de B
y C
)
Tengo dos ideas sobre cómo mejorar la situación actual, pero antes de dedicar tiempo a implementarlas, pensé en pedir consejo a la comunidad (después de todo, parece un "problema bastante común" que podría existir un patrón de diseño).
Para lo que vale, estas son las dos ideas que estaba pensando:
Slot-isation del espacio de etiqueta
En este escenario, dividiría toda la pantalla en "ranuras" para las etiquetas. Luego, cada vehículo siempre tendrá su etiqueta colocada en el vacío más cercano (vacío = no hay otros sprites en esa ubicación.
Búsqueda en espiral
Desde la ubicación del vehículo en la pantalla, trataría de colocar la etiqueta en ángulos crecientes y luego en radios crecientes, hasta que se encuentre una ubicación no superpuesta. Algo en la línea de:
try 0°, 10px
try 10°, 10px
try 20°, 10px
...
try 350°, 10px
try 0°, 20px
try 10°, 20px
...
Respuestas:
Esencialmente, este problema es similar a un problema para evitar colisiones. Sí, los aviones pueden volar a diferentes altitudes, pero sus etiquetas están a la misma "altitud".
Hay algoritmos como Evitar colisiones sin alinear , que sería un paso en la dirección correcta para usted. Por supuesto, para su situación, las etiquetas están "atadas" a sus planos, por lo que tienen un rango de movimiento limitado.
Si observa el comportamiento de flocado , desea implementar la primera "regla" de flocado: repulsión de corto alcance. Sin embargo, en lugar de "dirigirse" en la dirección que está lejos de los vecinos más cercanos, utilizará el vector "lejos" como ubicación de ubicación para su etiqueta.
Por ejemplo:
El círculo negro grande representa su área de influencia, el círculo verde representa las ubicaciones válidas para la etiqueta, el punto verde central es el plano que está considerando actualmente, el punto verde pequeño es el punto en el círculo elegido para la colocación de la etiqueta.
Ahora los puntos negros podrían representar otras etiquetas u otros planos. No estoy seguro de cuál funcionaría mejor, puede obtener una mejor evitación si fueran otras etiquetas, pero no estoy seguro. Obviamente, las flechas de "fuerza" son los vectores de dirección entre su plano actual y los "objetos de influencia". Finalmente, el cuadro es la etiqueta.
Entonces, usando su ejemplo anterior, creo que esto produciría algo como:
Con este método, hay algunas situaciones para las que tendrá que hacer casos especiales, como tres planos alineados verticalmente:
Las tres etiquetas pueden voltearse de derecha a izquierda, dependiendo de cómo haya definido las esquinas de su etiqueta. Básicamente, solo tendrás que estar atento a los ángulos alrededor del círculo donde tus etiquetas pueden cambiar de qué esquina están dibujadas: 0, 90, 180, 270.
Creo que al final, esto se vería ordenado, ver cómo las etiquetas se evitan entre sí. Si te distrae demasiado, quizás puedas redondear a los 10 grados más cercanos para un movimiento menos frecuente.
Perdón por los detalles extraños, pensé en la mayoría de estas cosas cuando estaba haciendo un menú radial para mi juego, pero creo que en esta forma "dinámica" funcionaría bastante bien.
fuente
Después de pensarlo, finalmente decidí implementar el método de búsqueda en espiral que describí brevemente en la pregunta original.
La razón es que el método Byte56 necesita un tratamiento especial para ciertas condiciones, mientras que la búsqueda en espiral no lo hace, y codifica de una manera realmente compacta . Además, la búsqueda de spriralling enfatiza encontrar el lugar más cercano al vehículo para colocar la etiqueta, lo cual es el factor principal para que el mapa sea legible.
Sin embargo, continúe votando su respuesta, ya que no solo es útil, ¡también está muy bien escrita!
Aquí hay una captura de pantalla del resultado logrado con el código en espiral:
Y aquí está el código que, aunque no es autónomo, da una idea de cuán simple es la implementación:
Nota 1 :
tag.place()
devuelve True si la etiqueta está completamente en el área visible de la pantalla / radar. Entonces esa línea dice "sigue en bucle si la etiqueta está fuera del radar o se superpone a otra cosa ..."Nota 2 :
tag.connector.update
es el método que dibuja la línea que conecta el icono del avión con la etiqueta / etiqueta con la información del texto.fuente