Girando hacia un punto en Box2D

Estoy usando Box2d como mi motor de física y estoy tratando de resolver lo que normalmente sería un problema simple, pero lo que se ha convertido en una pesadilla para mí y me impide terminar mi aplicación. (6 meses de trabajo)

Intenté implementar esto: (Ejemplo de implementación a continuación) http://box2d.org/forum/viewtopic.php?f=18&t=7306 pero tiene tres problemas. 1: Al alcanzar el ángulo superior se detiene y se dirige hacia el otro lado. (Ejemplo en loggings) 2: velocidad limitada, algunos objects necesitan girar rápido. 3: Los objects grandes con articulaciones mobilees se balancean por todo el lugar.

Tengo un ángulo deseado y quiero que mi cuerpo gire a diferentes velocidades (dependiendo de la configuration de velocidad de giro, ya que quiero grandes objects de giro lento).

Problemas con el código actual. 1: Objeto grande con una articulación mobile o gira muy rápido o se balancea constantemente. 2: El efecto rock existe en todo.

Editar Esto está dentro de un bucle de juego, por lo que tiene acceso a delta.

Código 1: bash de Box2D:

//Testing speed. float tempSpeed = MathUtils.PI; float currentAngle = getBody().getAngle() % MathUtils.PI2; float nextAngle = getBody().getAngle() + (getBody().getAngularVelocity() * update); float totalRotation = getDesinetworkingAngle() - nextAngle; //Assuming this tries to prevent the switch angle problem but limits the speed?? while ( totalRotation < -MathUtils.PI * tempSpeed ) totalRotation += MathUtils.PI2 * tempSpeed; while ( totalRotation > MathUtils.PI * tempSpeed ) totalRotation -= MathUtils.PI2 * tempSpeed; float desinetworkingAngularVelocity = totalRotation; float change = 1f * tempSpeed; //allow 1 degree rotation per time step desinetworkingAngularVelocity = Math.min(change, Math.max(-change, desinetworkingAngularVelocity)); float impulse = getBody().getInertia() * desinetworkingAngularVelocity; getBody().applyAngularImpulse(impulse, true); //Below shows an example of the top angle being switched. if(getFocus()){ Functions.log("currentAngle: " + getBody().getAngle() + " | nextAngle: " + nextAngle + " | totalRotation: " + totalRotation + " | desinetworkingAngularVelocity: " + desinetworkingAngularVelocity); } /* Log: nextAngle: -0.1850999 | totalRotation: 6.400846 | desinetworkingAngularVelocity: 3.1415927 Log: nextAngle: -0.02812685 | totalRotation: 6.2195992 | desinetworkingAngularVelocity: 3.1415927 Example of top angle being reached and switching back. Log: nextAngle: 0.21522963 | totalRotation: 5.948592 | desinetworkingAngularVelocity: 3.1415927 Log: nextAngle: 0.45278195 | totalRotation: 5.6859627 | desinetworkingAngularVelocity: 3.1415927 */ 

Código 2: mi bash deformado

 //Keep the angle within range. float currentAngle = getBody().getAngle() % 6.283185f; //Get the next angle. Use angle in next time step float nextAngle = currentAngle + (getBody().getAngularVelocity() * update); float totalRotationAngle = getDesinetworkingAngle() - nextAngle; //Keep the total rotation within range, so we don't spin all the way around when reaching the other side. while (totalRotationAngle < -MathUtils.PI) { totalRotationAngle += (MathUtils.PI2); } while (totalRotationAngle > MathUtils.PI) { totalRotationAngle -= (MathUtils.PI2); } //Do some other stuff. float desinetworkingAngularVelocity = totalRotationAngle * getRotationSpeed(); //Inertia is the amount of force requinetworking to rotate the object, without it it rotates really fast. //If we introduce it, we get more realistic results but the horrible rock. //float torque = (getBody().getInertia() * (desinetworkingAngularVelocity * this.turnSpeed)) * update; //Need inertia otherwise it can spins things right out the way. //float turnSpeed = (this.turnSpeed * (4f * (getDesinetworkingAngle()))); float torque = (desinetworkingAngularVelocity * (this.turnSpeed)); torque *= (getBody().getInertia()); torque *= update; //Apply torque. getBody().applyTorque(torque, false); 

Creo que quieres el método 1, no el método 2. ¿Supongo que tienes un índice de giro constante hacia el rumbo deseado? En ese caso, el torque, siendo la fuerza angular, no es lo que querrías usar aquí. (Necesitará un par infinito para get el arranque inmediato inicial, y luego un par infinito para detenerse inmediatamente en la dirección del objective) por lo que el primer método es más preciso.

Hay un par de lugares donde las variables no parecen tener las unidades correctas. Puede ayudar a escribir (en papel) qué unidades son cada una de sus variables y verificar las unidades con análisis dimensional.

Las siguientes dos líneas de código sujetan totalRotation / tempSpeed ​​a [-π, π]. Suponiendo que tempSpeed es tu velocidad angular máxima, esto no tiene mucho sentido para mí. Creo que deberías eliminar las partes de TempSpeed, y por lo tanto, la lógica es que la "rotation total" debe estar en ese range.

 //Assuming this tries to prevent the switch angle problem but limits the speed?? while ( totalRotation < -MathUtils.PI * tempSpeed ) totalRotation += MathUtils.PI2 * tempSpeed; while ( totalRotation > MathUtils.PI * tempSpeed ) totalRotation -= MathUtils.PI2 * tempSpeed; // should be: while (totalRotation < -MathUtils.PI) totalRotation += MathUtils.PI2; while (.. etc ..) 

Las dos líneas siguientes también me parecen incorrectas: la velocidad angular deseada es la velocidad angular (unidad: 1 / hora), y no una rotation (los radianes no tienen unidades), es necesario dividir por una variable de time. Además, la variable de cambio tiene algo que no permite una rotation de 1 grado por intervalo de time, está permitiendo una rotation de 180 grados por unidad de time (es decir, en segundo lugar).

 float desinetworkingAngularVelocity = totalRotation; float change = 1f * tempSpeed; //allow 1 degree rotation per time step // should be: float desinetworkingAngularVelocity = totalRotation / timedelta; float change = tempSpeed * delta; // allow 180 degree rotation per second 

Con estos cambios, debe eliminar el tambaleo, que fue causado por un cálculo de impulso incorrecto que siempre sobrepasa el valor deseado.