Assumirei que você tenha movimento fisicamente correto para sua nave, caso contrário, essa análise não será válida. Você precisa de algo mais forte que a eficiência para resolver esse problema corretamente.
Cada propulsor produzirá dois efeitos no movimento do navio: linear e angular. Estes podem ser considerados independentemente. Se o propulsor produz uma força f
em uma direção dir
e é deslocado do centro de massa por um vetor r
(não é o centro geométrico ou o centro do sprite!), O efeito no componente linear é:
t = f * dir // f is a scalar, dir is unit length
O efeito na velocidade angular é dado pelo torque:
tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product
t
é um vetor de força (ou seja, o impulso linear). tau
é um escalar assinado que, quando dividido pelo momento de inércia da massa, dará a aceleração angular. É importante que dir
e r
estão ambos no mesmo espaço de coordenadas, ou seja, tanto em coordenadas locais ou ambos em coordenadas mundiais.
A aceleração linear geral do navio é dada pela soma dos t
's' para cada propulsor dividido pela massa do navio. Da mesma forma, a aceleração angular é apenas a soma dos torques divididos pelo momento de inércia da massa (que é outro escalar).O navio não girará se o torque total for zero. Da mesma forma, ele não se moverá se o impulso total for zero. O torque de rechamada é escalar, mas o empuxo (a soma dos t
) é um vetor 2D.
O objetivo desta exposição é que agora podemos escrever nosso problema como um programa linear . Digamos primeiro que queremos que nosso navio gire sem se mover . Temos uma variável para cada propulsor, $ x_1, x_2, ... $, que é a quantidade de empuxo que o propulsor fornecerá. Um conjunto de restrições é:
0 <= x_i < fmax_i //for each i
onde fmax
está a força máxima para esse propulsor (isso nos permite ter forças mais fortes ou mais fracas). Em seguida, dizemos que ambas as igualdades:
0 = Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
Isso codifica a restrição de que não aplicaremos uma aceleração linear, dizendo que o impulso total é zero (impulso é um vetor, portanto, apenas dizemos que cada parte é zero).
Agora queremos que nosso navio gire. Presumivelmente, queremos fazê-lo o mais rápido possível, e 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>
Resolução para o x_i
enquanto satisfaz as desigualdades e igualdades acima, enquanto maximiza a soma acima, nos dará o impulso desejado. A maioria das linguagens de programação possui uma biblioteca de LP disponível para elas. Basta colocar o problema acima e ele produzirá sua resposta.
Um problema semelhante nos permitirá avançar sem virar. Digamos que reescrevemos nosso problema em um sistema de coordenadas no qual queremos avançar na direção x positiva. Então as restrições são:
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
Com a restrição de que os propulsores só podem produzir impulso em uma única direção, haverá limites para o tipo de rotações e velocidades lineares que você será capaz de atingir. Isso se manifestará como a solução sendo0 = x_1 = x_2 = ... = x_n
, o que significa que você nunca chegará a lugar algum. Para mitigar isso, sugiro adicionar um par de propulsores pequenos e fracos (digamos 5% ou 10%) para cada jogador colocado o propulsor a 45 graus de cada lado. Isso dará à solução mais flexibilidade, pois elas podem ser usadas para neutralizar os efeitos secundários fracos dos propulsores principais.
Finalmente, para até 100 propulsores, a solução para o LP é rápida o suficiente para ser feita por quadro. No entanto, como a solução não depende da localização ou do estado atual, você pode pré-calcular a solução para cada combinação razoável de entradas do controlador sempre que a forma for alterada (isso inclui adicionar não propulsores que alteram o momento de inércia ou a massa do navio, porque então os propulsores estão em um local diferente em relação ao centro de massa!). São 24 possibilidades (ie 8 direções vezes (rotação à esquerda, sem rotação, rotação à direita)).