Balanceamento dinâmico do propulsor da nave espacial

14

As naves espaciais do meu jogo deveriam ser construídas por jogadores, com uma quantidade arbitrária de propulsores conectados a qualquer lugar com qualquer rotação. Atualmente, tenho algum código sujo para girar o navio para um determinado ângulo (acelerando e desacelerando).

Aqui está um exemplo de um navio simétrico voltado para onde a linha vermelha aponta, sendo instruído a girar para a esquerda.

Navio

No entanto, como você pode imaginar, dependendo de onde o jogador colocou os propulsores, às vezes forças lineares indesejadas estão afetando o navio. Nesse caso, o navio começa a avançar.

Estou analisando se é possível encontrar o impulso máximo que um propulsor pode aplicar para não causar velocidade linear. (No caso acima, não haveria, pois não há nada para neutralizar as forças dos propulsores traseiros, e os da frente se matam).

O que eu vim até agora é uma fórmula para determinar a "eficiência da rotação", por exemplo, quanta rotação é causada em relação ao movimento linear.

a - vetor de posição para o propulsor a b - vetor de posição para o propulsor b v1 - força do propulsor a v2 - força do propulsor b

eficiênciaDelta = a.cross (v1) / | v1 | - (a.cross (v1) + b.cross (v2)) / | v1 + v2 |

, basicamente "a.cross (v1 * t) / | v1 |" é suposto ser a eficiência da curva. E então subtraímos pela eficiência de rotação dos propulsores combinados, para ver se vale a pena disparar o novo propulsor.

O problema surge quando percebo que os propulsores não podem ser ligados / desligados, mas podem variar de 0 a 1. E como proceder quando o jogador deseja que o navio avance. Obviamente, haveria um equilíbrio de quanto girar / mover.

Como não sou cientista de foguetes, espero que alguém possa me dizer se é possível calcular o acelerador de cada propulsor dessa maneira e me empurrar na direção certa.

Obrigado por tomar o tempo! / Kim

Kim
fonte
3
Comecei no mesmo caminho, mas com muitas configurações, é impossível girar e não traduzir. Então você tira a rotação? Ou você permite a tradução? Por fim, cabe ao usuário projetar o navio. Para a minha demonstração disso, eu fingi. Relacionado: gamedev.stackexchange.com/questions/58216/… , gamedev.stackexchange.com/questions/40615/…
MichaelHouse
Eu segui um caminho semelhante e acabei escrevendo uma demo nesta página . À medida que você move os propulsores (arrastá-los no navio para definir a posição e o poder), ele desenha três formas. A intuição é que você pode pensar em todos os movimentos possíveis como um ponto no espaço 3D (x, y, rotação), e limitar-se a 0-1 é uma restrição nesse espaço. Então você acaba com uma forma 3d contendo todos os movimentos possíveis. Se você quiser sem velocidade linear que você está olhando para o (x = 0, y = 0), linha em que o espaço (Q, W, E, é tudo 0 na minha demo)
amitp

Respostas:

7

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 fem uma direção dire é 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 dire restã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 fmaxestá 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)).


fonte
Muito bem explicado!
22714 Kim
1
O que Sum_isignifica neste contexto?
S. Tarık Cetin 5/17/17
1

Meu primeiro pensamento foi uma solução puramente empírica, que é simular a sonda em um ambiente de sandbox para diferentes graus de empuxo para descobrir como ela se comporta. Em vez de equilibrar muita matemática complexa na busca de uma solução determinística, você pode alcançá-la numericamente, por exemplo, usando o método de newtons. Exemplo:

O intervalo de empuxo é de 0 a 1000, onde 1000 é MUITO.

Passo 1

Simule com confiança (0 + 1000) / 2 = 500. Resultado: muita confiança

Passo 2

O intervalo agora é de 0 a 500 Simule com confiança (0 + 500) / 2 = 250. Resultado: muita confiança

Etapa 3

O intervalo agora é de 0 a 250 Simular com confiança (0 + 250) / 2 = 125 Resultado: confiança insuficiente

Passo 4

O intervalo agora é de 125 a 250 Simule com confiança (125 + 250) /2=187.5 Resulte em muita confiança

Etapa # 5 O intervalo agora é de 125 a 187,5 Simule com confiança (125 + 187,5) /2=156,25 O resultado é pouca confiança

Etapa 6: o intervalo agora é de 156,25 a 187,5 O intervalo está abaixo do limite de 35, o que significa que é uma estimativa suficientemente boa.

Resultado final = (187.5 + 156.25) / 2 = 171.875

Lennart Rolland
fonte