¿Cómo encontrar celdas de cuadrícula 2D barridas por un círculo en movimiento?

9

Estoy haciendo un juego basado en una cuadrícula 2D, con algunas celdas pasables y otras no. Los objetos dinámicos pueden moverse continuamente, independientemente de la cuadrícula, pero deben colisionar con celdas intransitables.

Escribí un algoritmo para rastrear un rayo contra la cuadrícula, que me da todas las celdas que se cruzan. Sin embargo, el objeto real no tiene un tamaño de punto; Actualmente los estoy representando como círculos. Pero no puedo encontrar un algoritmo efectivo para trazar un círculo en movimiento. Aquí hay una foto de lo que necesito: ingrese la descripción de la imagen aquí

Los números muestran en qué orden el círculo choca con las celdas de la cuadrícula. ¿Alguien sabe el algoritmo para encontrar estas colisiones? Preferiblemente en C #.

Actualización El círculo puede ser más grande que una sola celda de cuadrícula.

No importa
fuente
mmh por qué 3 chocan ANTES de 4?
FxIII
@FxIII Realmente moví el círculo en la imagen, y dio 3 antes de 4. Solo apenas, pero aún antes.
importa

Respuestas:

6

Creo que tu dibujo es un poco engañoso porque eliges dibujar trazos desde el punto de la tangente del círculo hasta tu dirección de movimiento. Puedo ver que las colisiones con los bordes de la cuadrícula ocurren cuando los puntos SUPERIOR e IZQUIERDO de su círculo tocan un borde.

Deje que C sea ​​su centro y r el radio para que P ' = C + ( r , 0) y P " = C + (0, r).

Si D es tu vector de dirección (el versor) tienes dos líneas:

R '= D · t + P' ,

R "= D · t + P"

Simplemente tiene que encontrar la intersección de esas líneas con las líneas de ecuación:

y = i e y = i que son los bordes de su cuadrícula!

La solución es fácil porque simplemente tiene que considerar la componente x o y de R 'y R ". Encontrará el valor de t s para cada sección y los puntos para esas t , simplemente ordene esos puntos por t y usted están hechos.

Creo que puedes decir fácilmente qué celda es golpeada si conoces el punto de intersección.

Esto funciona si r <1 (el ancho y la altura de la celda).

Funciona también para los otros casos simplemente haciendo alguna consideración sobre P ' y P " . Elegimos ARRIBA e IZQUIERDA debido a la dirección, ABAJO y DERECHA deben considerarse para la dirección opuesta, entiendes por qué.

Ahora mira esta imagen: gran círculo

El círculo es más grande que una sola celda y suponemos que va en la misma dirección que su dibujo. P1 es el primer punto que tocará, P2 es el segundo, P3 es inútil porque está en la mitad inferior. Lo que debe hacer es emitir rayos desde P1 y P2 como vimos antes y hacer lo mismo para las líneas verticales.

En general, tendrás otros puntos de partida junto con los SUPERIORES y los IZQUIERDOS desde donde disparas tus rayos, cuanto más grande sea tu círculo, más rayos lanzarás.

Para ser honesto, puedes evitar disparar todos esos rayos haciendo alguna consideración geométrica, pero eso puede hacer que las cosas sean más difíciles de entender.

FxIII
fuente
Sí, pensé en los puntos P 'y P ", pero no pude averiguar qué hacer cuando el círculo es más grande que una sola celda. Los puntos adicionales realmente tienen sentido (y obviamente solo necesito agregar rayos entre P' y P ")
importa
Se pueden hacer consideraciones geométricas que simplifiquen los cálculos, pero el uso de la implementación puede llevarlo a los mismos resultados por experiencia.
FxIII
¿Está claro que debe probar las líneas de cuadrícula horizontales y verticales por separado?
FxIII
Creo que también debe verificar cuándo el círculo cubre un vértice de la cuadrícula, porque el círculo colisionará con la celda diagonalmente adyacente en su esquina, pero no necesariamente será el punto superior / izquierdo / inferior / derecho del círculo que lo toca primero (y detectará la colisión demasiado pronto). Ejemplo: cuadrados 3,4,5 en el diagrama de ejemplo en la pregunta. Se golpean en orden (3 luego 4 y luego 5) pero su algoritmo detectaría 4 y 5 simultáneamente.
finnw
@finnw se tocan simultáneamente solo si el ciclo viaja exactamente en la dirección de la bisectriz.
FxIII
1

Si desea usar su algoritmo de colisión de rayos, puede elegir ocho puntos en cada círculo (en incrementos de 45 grados, alineados con su cuadrícula cuadrada), y usar la colisión de rayos entre los puntos correspondientes (es decir, desde la parte superior de uno círculo a la parte superior de la otra). La unión de todas estas colisiones de rayos es el conjunto completo de células intersectadas.

Probablemente podría mejorar esto un poco, por ejemplo, utilizando el segmento de línea desde el centro de un círculo hasta el centro del otro, pero extendido a cada lado por el radio del círculo, así como los segmentos de línea paralelos en cualquier lado en las extremidades de los círculos.

TreDubZedd
fuente
8 rayos probablemente garantizarán todas las intersecciones, pero no las darán en el orden correcto. Y para colisiones necesito orden, no solo una lista de celdas.
importa
Aumente su algoritmo de colisión de rayos para retener un valor t para cada colisión. Cuando obtiene la unión de celdas, puede ordenar el valor t para obtener el orden correcto.
TreDubZedd
Pero, ¿cómo puedo comparar el valor t de diferentes rayos?
importa
Si siempre se origina en el mismo círculo, sus puntos de intersección serán distancias desde ese círculo. Cuando veas una celda que ya has visto, si el valor t de la colisión actual es más pequeño que el anterior, úsalo ... de lo contrario, descarta la intersección (manteniendo el original).
TreDubZedd
1
Es posible que pueda salirse con solo dos rayos en los lados del círculo perpendicular al movimiento, luego puede ver qué fichas golpean los rayos y puede verificar el resto para ver si sus centros caen entre los dos rayos. Lo único que debería fallar serían las cosas que colisionan al principio o al final del círculo, pero son solo dos círculos y se pueden manejar fácilmente. Puede ser un poco más lento que ocho rayos, no estoy seguro; pero no necesitaría escalar el número según el tamaño del círculo.
Lunin
1

No digo que sea una analogía perfecta, pero podrías pensar en el algoritmo de línea de Bresenham . Una modificación de este algoritmo o una de sus extensiones podría ser útil, especialmente si lo combina con algunas de las otras publicaciones y comentarios. Por lo general, este algoritmo no se preocupa por ordenar, pero creo que podría agregarlo de manera bastante trivial.

Ryan
fuente
Estaba pensando en esto también, pero en mi opinión, este no es el algoritmo correcto. Bresenham elige solo un píxel, lo necesita todo. Y sería difícil adaptar Bresenham al círculo en lugar de un solo píxel.
zacharmarz
El rastreador que utilizo está basado en el algoritmo de Bresenham. Tengo problemas para generalizarlo de una línea delgada a una "gruesa", específicamente barrida en círculo.
importa