He estado probando algo de física de la cuerda recientemente, y he descubierto que la solución "estándar" - hacer una cuerda a partir de una serie de objetos unidos con resortes o juntas - no es satisfactoria. Especialmente cuando el balanceo de la cuerda es relevante para el juego. Realmente no me importa la capacidad de una cuerda para envolverse o ceder (de todos modos, esto puede ser falso para las imágenes).
Para el juego, lo importante es la capacidad de la cuerda de envolver el entorno y luego desenvolverse. Ni siquiera tiene que comportarse como una cuerda; un "cable" hecho de segmentos de línea recta funcionaría. Aquí hay una ilustración:
Esto es muy similar a la "Cuerda Ninja" del juego Worms.
Como estoy usando un motor de física 2D, mi entorno está formado por polígonos convexos 2D. (Específicamente estoy usando SAT en Farseer).
Entonces mi pregunta es esta: ¿Cómo implementaría el efecto de "envoltura"?
Parece bastante obvio que el cable estará formado por una serie de segmentos de línea que se "dividen" y "unen". Y el segmento final (activo) de esa línea, donde se une el objeto en movimiento, será una unión de longitud fija.
Pero, ¿cuál es el algoritmo matemático involucrado para determinar cuándo y dónde se debe dividir el segmento de línea activo? ¿Y cuándo debe unirse al segmento anterior?
(Anteriormente, esta pregunta también se refería a hacer esto para un entorno dinámico; he decidido dividirlo en otras preguntas).
fuente
Ha pasado un tiempo desde que jugué Worms, pero por lo que recuerdo, cuando la cuerda se enrolla alrededor de las cosas, solo hay una sección (recta) de cuerda que se mueve en cualquier momento. El resto de la cuerda se vuelve estático.
Entonces hay muy poca física real involucrada. La sección activa se puede modelar como un resorte rígido único con una masa en el extremo
Lo interesante será la lógica para dividir / unir secciones inactivas de la cuerda hacia / desde la sección activa.
Me imagino que habría 2 operaciones principales:
'Split': la cuerda ha cruzado algo. Divídalo en la intersección en una sección inactiva y la nueva sección más corta y activa
'Unir': la cuerda activa se ha movido a una posición donde la intersección más cercana ya no existe (¿esto puede ser una simple prueba de ángulo / punto del producto?). Vuelva a unirse a 2 secciones, creando una nueva sección más larga y activa
En una escena construida a partir de polígonos 2D, todos los puntos de división deben estar en un vértice en la malla de colisión. La detección de colisión puede simplificarse a lo largo de las líneas de 'Si la cuerda pasa sobre un vértice en esta actualización, ¿dividir / unir la cuerda en ese vértice?
fuente
Mira cómo se implementó la cuerda ninja en Gusanos :
Extracto relevante de ninjarope.cpp :
fuente
Me temo que no puedo darle un algoritmo concreto en la parte superior de mi cabeza, pero se me ocurre que solo hay dos cosas importantes para detectar una colisión con la cuerda ninja: cualquiera y todos los vértices potencialmente colisionantes sobre los obstáculos. dentro de un radio de la última "división" igual a la longitud restante del segmento; y la dirección actual de oscilación (en sentido horario o antihorario). Si creó una lista temporal de ángulos desde el vértice "dividido" a cada uno de los vértices cercanos, su algoritmo solo necesitaría preocuparse si su segmento estaba a punto de oscilar más allá de ese ángulo para cualquier vértice dado. Si es así, debe realizar una operación de división, que es fácil como un pastel: es solo una línea desde el último vértice de división hasta la nueva división, y luego se calcula un nuevo resto.
Creo que solo importan los vértices. Si está en peligro de golpear un segmento entre los vértices de un obstáculo, entonces su detección de colisión normal para el tipo que cuelga al final de la cuerda debería funcionar. En otras palabras, su cuerda solo se "enganchará" esquinas de todos modos, por lo que los segmentos intermedios no serán importantes
Lo siento, no tengo nada concreto, pero espero que eso te lleve a donde necesitas estar, conceptualmente, para que esto suceda. :)
fuente
Aquí hay una publicación que tiene enlaces a documentos sobre tipos similares de simulaciones (en contextos de ingeniería / académicos en lugar de juegos): https://gamedev.stackexchange.com/a/10350/6398
He probado al menos dos enfoques diferentes para la detección de colisión + respuesta para este tipo de simulación de "cable" (como se ve en el juego Umihara Kawase); al menos, creo que esto es lo que buscas: no parece haber un término específico para este tipo de simulación, solo tiendo a llamarlo "cable" en lugar de "cuerda" porque parece que la mayoría de las personas considere "cuerda" como sinónimo de "una cadena de partículas". Y, si desea el comportamiento de cuerda de ninja (es decir, puede empujar Y tirar), esto es más como un cable rígido que una cuerda. De todas formas..
La respuesta de Pekuja es buena, puede implementar la detección de colisión continua resolviendo el momento en que el área firmada de los tres puntos es 0.
(No puedo recordar completamente OTOH, pero puede abordarlo de la siguiente manera: encuentre el tiempo t cuando el punto a está contenido en la línea que pasa por b, c, (creo que hice esto resolviendo cuándo dot (ab, cb) = 0 para encontrar valores de t), y luego dado un tiempo válido 0 <= t <1, encuentre la posición paramétrica s de a en el segmento bc, es decir, a = (1-s) b + s c y si a está entre byc (es decir, si 0 <= s <= 1) es una colisión válida.
AFAICR también puede abordarlo al revés (es decir, resolver s y luego enchufarlo para encontrar t), pero es mucho menos intuitivo. (Lo siento si esto no tiene sentido, ¡no tengo tiempo para desenterrar mis notas y han pasado algunos años!))
Por lo tanto, ahora puede calcular todos los momentos en que ocurren los eventos (es decir, los nodos de cuerda deben insertarse o eliminarse); procesar el primer evento (insertar o eliminar un nodo) y luego repetir / repetir hasta que no haya más eventos entre t = 0 y t = 1.
Una advertencia sobre este enfoque: si los objetos que la cuerda puede envolver son dinámicos (especialmente si los está simulando Y sus efectos en la cuerda, y viceversa), entonces puede haber problemas si esos objetos se enganchan / atraviesan otro: el cable puede enredarse. Y definitivamente será un desafío evitar este tipo de interacción / movimiento (las esquinas de los objetos que se deslizan entre sí) en una simulación física de estilo box2d ... pequeñas cantidades de penetración entre objetos es un comportamiento normal en ese contexto.
(Al menos ... esto fue un problema con una de mis implementaciones de "cable").
Una solución diferente, que es mucho más estable pero que pierde algunas colisiones en ciertas condiciones es simplemente usar pruebas estáticas (es decir, no se preocupe por ordenar por tiempo, simplemente subdividir recursivamente cada segmento en colisión a medida que los encuentre), que puede ser mucho más robusto: el cable no se enredará en las esquinas y pequeñas cantidades de penetración estarán bien.
Creo que el enfoque de Pekuja también funciona para esto, sin embargo, hay enfoques alternativos. Un enfoque que he usado es agregar datos auxiliares de colisión: en cada vértice convexo v del mundo (es decir, las esquinas de las formas alrededor de las cuales puede envolver la cuerda), agregue un punto u formando el segmento de línea dirigida uv, donde u apunte "dentro de la esquina" (es decir, dentro del mundo, "detrás" de v; para calcular u puede lanzar un rayo hacia adentro desde v a lo largo de su normal interpolado y detenerse a cierta distancia después de v o antes de que el rayo se cruce con un borde del mundo y sale de la región sólida, o simplemente puede pintar manualmente los segmentos en el mundo usando una herramienta visual / editor de niveles).
De todos modos, ahora tienes un conjunto de "líneas de esquina" uv; para cada uv y cada segmento ab en el cable, verifique si ab y uv se cruzan (es decir, consulta de intersección estática, booleana lineseg-lineseg); si es así, recurse (divida el lineseg ab en av y vb, es decir, inserte v), registrando en qué dirección se dobló la cuerda en v. Luego, para cada par de linesegs vecinos ab, bc en el cable, pruebe si la dirección de curva actual en b es lo mismo que cuando se generó b (todas estas pruebas de "dirección de curvatura" son solo pruebas de área con signo); de lo contrario, combine los dos segmentos en ac (es decir, elimine b).
O tal vez me fusioné y luego me separé, lo olvido, ¡pero definitivamente funciona en al menos una de las dos posibles órdenes! :)
Teniendo en cuenta todos los segmentos de cable calculados para el cuadro actual, puede simular una restricción de distancia entre los dos puntos finales del cable (e incluso puede involucrar los puntos interiores, es decir, los puntos de contacto entre el cable y el mundo, pero eso es un poco más complicado) )
De todos modos, espero que esto sea de alguna utilidad ... los documentos en la publicación que he vinculado también deberían darte algunas ideas.
fuente
Un enfoque para esto es modelar la cuerda como partículas colisionables, conectadas por resortes. (bastante rígidos, posiblemente incluso como un hueso en su lugar). Las partículas chocan con el medio ambiente, asegurándose de que la cuerda se enrolle alrededor de los artículos.
Aquí hay una demostración con fuente: http://www.ewjordan.com/rgbDemo/
(Muévase hacia la derecha en el primer nivel, hay una cuerda roja con la que puede interactuar)
fuente