Asumiré que tienes un movimiento físicamente correcto para tu nave, ya que de lo contrario este análisis no se mantendrá. Necesita algo más fuerte que la eficiencia para resolver este problema correctamente.
Cada propulsor producirá dos efectos sobre el movimiento de la nave: lineal y angular. Estos pueden considerarse de forma independiente. Si el propulsor produce una fuerza f
en una dirección dir
y está desplazado del centro de masa por un vector r
(¡no el centro geométrico o el centro del sprite!), Entonces el efecto sobre el componente lineal es:
t = f * dir // f is a scalar, dir is unit length
El efecto sobre la velocidad angular viene dado por el par:
tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product
t
es un vector de fuerza (es decir, el empuje lineal). tau
es un escalar con signo que, cuando se divide por el momento de inercia de la masa, dará la aceleración angular. Es importante que dir
y r
son a la vez en el mismo espacio de coordenadas, es decir, tanto en coordenadas locales o ambos en coordenadas mundiales.
La aceleración lineal general de la nave viene dada por la suma de los t
's para cada propulsor dividido por la masa de la nave. Del mismo modo, la aceleración angular es solo la suma de los pares divididos por el momento de inercia de la masa (que es otro escalar). El barco no girará si el par total es cero. Del mismo modo, no se moverá si el empuje total es cero. El par de recuperación es escalar pero el empuje (la suma de los t
's) es un vector 2D.
El punto de esta exposición es que ahora podemos escribir nuestro problema como un programa lineal . Digamos primero que queremos que nuestro barco gire sin moverse . Tenemos una variable para cada propulsor, $ x_1, x_2, ... $, que es la cantidad de empuje que proporcionará el propulsor. Un conjunto de restricciones es:
0 <= x_i < fmax_i //for each i
¿Dónde fmax
está la fuerza máxima para ese propulsor (esto nos permite tener más fuertes o más débiles). A continuación, decimos que ambas igualdades:
0 = Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
Esto codifica la restricción de que no aplicaremos una aceleración lineal, al decir que el empuje total es cero (el empuje es un vector, por lo que simplemente decimos que cada parte es cero).
Ahora queremos que nuestro barco gire. Presumiblemente, queremos hacerlo lo más rápido posible, por lo que queremos:
max (Sum_i x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0>
Resolver los problemas x_i
mientras satisface las desigualdades e igualdades anteriores, mientras maximiza la suma anterior, nos dará el empuje deseado. La mayoría de los lenguajes de programación tienen una biblioteca LP disponible para ellos. Simplemente coloque el problema anterior y producirá su respuesta.
Un problema similar nos permitirá movernos sin girar. Digamos que reescribimos nuestro problema en un sistema de coordenadas en el que queremos movernos en la dirección x positiva. Entonces las restricciones son:
0 <= x_i < fmax_i //for each i
max Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
0 = (Sum_i x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0> // as before
Con la restricción de que los propulsores solo pueden producir empuje en una sola dirección, habrá límites para el tipo de rotaciones y velocidades lineales que podrá lograr. Esto se manifestará como la solución 0 = x_1 = x_2 = ... = x_n
, lo que significa que nunca llegarás a ningún lado. Para mitigar esto, sugiero agregar un par de propulsores pequeños y débiles (por ejemplo, 5% o 10%) para cada jugador que coloque el propulsor a 45 grados a cada lado. Esto le dará más flexibilidad a la solución, ya que se pueden usar para contrarrestar los débiles efectos secundarios de los propulsores principales.
Finalmente, para hasta unos 100 propulsores, la solución al LP es lo suficientemente rápida como para hacerse por cuadro. Sin embargo, debido a que la solución no depende de la ubicación o el estado actual, puede calcular previamente la solución para cada combinación de entrada de controlador razonable cada vez que cambie la forma (esto incluye agregar no impulsores que cambian el momento de inercia o la masa de la nave, ¡porque entonces los propulsores están en una ubicación diferente en relación con el centro de masa!). Esto es 24 posibilidades (es decir, 8 direcciones veces {giro a la izquierda, sin rotación, giro a la derecha}).