El cuerpo perdió un componente de velocidad al golpear una panetworking

Estoy creando un juego de Breakout usando Box2D (de LibGdx si le interesa). Todo funciona bien hasta que la pelota golpea la panetworking cuando se mueve con un ángulo muy pequeño. Por favor mira la image para más detalles:

enter image description here

Traté de establecer la fricción de la panetworking en 0 y la restitución en 1, así como la fricción y la restitución de la bola, pero todavía se mueve a lo largo de la panetworking (no tengo Gravedad mundial). Esto también le sucede a la panetworking vertical si el ángulo es lo suficientemente pequeño, perderá velocidad X.

¿Cómo puedo mover la pelota como esperaba? Si no hay fricción, ¿qué causó el problema?

EDITAR : solo en el caso de LibGdx, esta es una solución:

World.setVelocityThreshold(float threshold); 

Lo configuré en 0.1f, y me ayudó. Si encuentra un problema, tal vez 0 puede ayudar, pero no se recomienda.

Qué esta pasando

En primer lugar, tenga en count que este comportamiento no es específico de colisiones oblicuas. A continuación se muestra un ejemplo de dos bolas colisionando con una panetworking. Todos los dispositivos tienen m_restitution = 1.0 y m_friction = 0.0 . La bola de la izquierda viaja con v = 0,1 y la bola de la derecha tiene v = 0,1.01 .

enter image description here

Hace un time encontré tres preguntas similares formuladas en los foros de box2d, que sugieren la disminución de un valor en b2Settings.h, b2_velocityThreshold .

No b2_velocityThreshold mucho en encontrar el bloque de código donde se hace reference a b2_velocityThreshold . Resultó ser la línea 211 del file b2ContactSolver.cpp , y dentro de la function b2ContactSolver::initializeVelocityConstraints : 1

Es aquí donde el factor de polarización de velocidad se establece en function de si la velocidad relativa supera o no a b2_velocityThreshold . Ese factor de polarización de velocidad se reference en la function iterada b2ContactSolver::SolveVelocityConstraints . Cuando la velocidad de polarización no está establecida (por defecto es cero), el impulso acumulado inicial se convierte en lo justo para contrarrestar el impulso inicial de la pelota, y se pega a la panetworking.

Intenté comprender por b2_velocityThreshold sale el b2_velocityThreshold en primer lugar (muchas búsquedas web) y no he encontrado una respuesta definitiva. Lo mejor que puedo hacer es citar a Erin Catto (autora de box2d) que publicó en uno de los temas anteriores:

Si configuras [ b2_velocityThreshold ] a cero, la restitución distinta de cero hará que tus cuerpos reboten para siempre.

Así que estoy extrapolando que este comportamiento se implementa por el bien de los juegos con bolas que rebotan, donde las bolas con restitución 0<e<1 nunca dejarían de rebotar (aunque las alturas de los rebotes llegarían a ser muy pequeñas). Esto desperdiciaría toneladas de time de CPU creando / eliminando el contacto entre los dos cuerpos, y además el cuerpo que rebotaba nunca dormiría.

Soluciones recomendadas

Solución 1
La recomendación de los hilos del foro anterior es networkingucir el parámetro en b2Settings.h:

#define b2_velocityThreshold 1.0f

Un umbral de velocidad para colisiones elásticas. Cualquier colisión con una velocidad lineal relativa por debajo de este umbral se tratará como inelástica.

Desafortunadamente, este parámetro es una constante #define y, por lo tanto, no se puede editar a less que se vuelva a comstackr box2d. Supongo que no desea volver a comstackr libgdx para hacer esto.

Solución 2
Zee estaba en el path correcto con su respuesta, pero necesita un poco más de detalle. Un buen enfoque para hacer esto es utilizar devoluciones de llamada de colisión como usted sugiere. Parece que sabes lo que estás haciendo con este, así que no voy a entrar en detalles aquí.

Solución 3
Este es un truco, y solo estoy recomendando esto porque dices que estás trabajando en un clon de ruptura, que solo tiene un par de partes mobilees.

Deberías dejar casi todo como está, pero boost la velocidad de tu bola por un factor de s donde s>1 . Si s es lo suficientemente alto, entonces las colisiones muy oblicuas seguirán teniendo una velocidad relativa significativa y, por lo tanto, activarán la configuration de polarización de la velocidad, en caso contrario, se ramificará en el código al que se hace reference, y su bola casi siempre rebotará. El problema es que ahora tu juego es imposible porque la pelota es tan rápida y el jugador no puede mantener el ritmo. Para compensar esto, simplemente multiplique su paso de time por un factor de 1/s antes de llamar a b2World::Step . De esa forma, box2d técnicamente estará operando en camera lenta, pero como tu bola se ha acelerado en la misma cantidad, todo se verá normal.

Aquí hay 2 gifs más. El izquierdo muestra una bola con v=1,1 y un tamaño de paso de time ts = dt . El segundo es con v=2,2 (magnitud duplicada), y el tamaño del paso de time ts = 0.5*dt . Voila:

wall_stickwall_bounce

¡Espero que esto ayude!

1 Este es el único lugar que pude encontrar donde se hace reference a ese parámetro de umbral. (es decir, tiene el mismo efecto para todos los types de contacto, independientemente de las forms involucradas en la colisión)

No estoy familiarizado con libgdx, así que me disculpo si esto podría estar un poco fuera de lugar; pero ¿no necesitas un script para la class wall? En este momento parece que la panetworking simplemente está actuando como si debiera reactjsr y no hace nada para afectar el movimiento de la bola, por lo que la bola continuará yendo en la misma dirección en la flecha negra.

Haga que sea así si se golpea la panetworking, se multiplicará por -1 el componente vectorial del eje Y de la bola. Y si golpea cualquiera de las panetworkinges derecha / izquierda, multiplica por -1 el componente del eje X.