Estou desenvolvendo um jogo espacial 2D sem atrito e estou achando muito fácil fazer com que um míssil local orbite seu alvo. Estou curioso sobre estratégias anti-órbitas.
Um exemplo simples é um míssil local que simplesmente acelera diretamente em direção ao seu alvo. Se esse alvo se mover perpendicularmente à trajetória do míssil, então pare, a aceleração do míssil em direção ao alvo não seria suficiente para superar sua própria velocidade, e o míssil poderia ser colocado em órbita ao redor do alvo, como mostrado:
- No quadro 1, o míssil está indo direto para o alvo, sem problemas.
- No quadro 2, o alvo foi movido para uma nova posição, como demonstrado. O míssil continua a acelerar diretamente em direção ao alvo (em vermelho), enquanto ainda se move em direção a onde o alvo costumava estar (em preto) devido à sua velocidade existente.
- No quadro 3, a velocidade do míssil continua carregando o míssil pelo lado do alvo (preto), enquanto o vetor de aceleração tenta desesperadamente puxar o míssil em direção ao alvo.
- Nos quadros 4 e além, o míssil cai em uma órbita potencialmente estável ao redor do alvo e nunca atinge seu objetivo. As setas pretas indicam um vetor de velocidade, enquanto as linhas vermelhas indicam vetores de aceleração no mesmo momento.
Considerando que não há atrito no espaço, não há nada para diminuir a velocidade do míssil e colapsar a órbita. Uma solução possível seria mirar "atrás" do alvo, e isso faria com que a órbita se fechasse, mas como isso é feito do ponto de vista da programação?
Como faço para que um míssil local alcance seu objetivo?
Respostas:
Primeiro, você deve fazer todos os cálculos sobre qual aceleração aplicar no quadro de referência do míssil (é aí que o míssil está estacionário e tudo o mais se move ao seu redor, também chamado de "coordenadas de objeto" ou "coordenadas locais" nos mecanismos de jogo, embora no nosso caso desejemos que a velocidade seja exatamente igual a zero).
A idéia, então, não é apontar para o alvo, mas apontar para o local em que o alvo estará no tempo estimado do impacto. Portanto, o algoritmo geral se parece com isso:
Estime quanto tempo levará para o míssil atingir o alvo. Se o alvo estiver voando diretamente para ele (lembre-se, o míssil está parado ), pode ser tão simples quanto calcular distância / velocidade ; em outros casos, pode ser mais complicado. Se o alvo puder fugir e você não conseguirá fazer uma estimativa perfeita, então não há problema em não ser muito preciso.
Supondo velocidade constante (estimativa de 1º grau) ou aceleração constante (estimativa de 2º grau) do alvo, calcule onde estará no tempo estimado acima.
Calcule a aceleração que levará o míssil a estar aproximadamente no mesmo local ao mesmo tempo.
Re-projete a aceleração de volta do quadro de referência do míssil para o global, use isso.
A parte importante aqui é obter a estimativa de tempo no campo aproximado e não esquecer as capacidades de aceleração do míssil ao fazê-lo. Por exemplo, uma estimativa melhor para "o alvo está bem à nossa frente e voando em nossa direção" seria resolver a equação.
distância = velocidade x tempo + 1/2 x aceleração x tempo 2
... para o tempo (usar a velocidade negativa para objetos voadores reta afastado do míssil), com a solução que você está procurando usando o padrão fórmula quadrática sendo ...
tempo = (√ ( velocidade 2 + 2 x aceleração x distância ) - velocidade ) / aceleração
Adicionar parâmetros adicionais - arraste, por exemplo - rapidamente transforma isso em equações diferenciais sem soluções algébricas. Este é por isso que a ciência do foguete é tão difícil.
fonte
@ Martin Sojka já lhe disse o que fazer. Em vez de melhorar sua resposta, quero propor uma outra abordagem mais simples: DELOCK
Como eu disse na trajetória projetada de um veículo? , objetos com capacidades limitadas de direção "projetam" alguns círculos de sombra: duas regiões que não podem ser alcançadas via direção direta (um toro e um hipertorso em dimensões mais altas).
Quando você vê que o alvo está entrando em uma dessas sombras de direção, pode parar de direcionar o alvo e manter outra direção por um período limitado de tempo.
O gatilho de bloqueio pode ser calculado facilmente aproximando seus toros com um cone (duplo) *:
Você precisa simplesmente calcular o produto escalar entre o vetor de direção (normalizado) e o vetor de deslocamento de destino ( Target - Object / | Target - Object |).
À medida que o produto escalar chega a zero, a direção do seu alvo fica perpendicular à sua direção, levando a uma trajetória circular **. Quando o alvo cai na região ciana, você pode inverter a direção da direção, para colocá-lo fora da área inacessível e voltar a chegar.
* Para ser sincero, este não é um cone ... é outro tipo de superfície governada gerada pela (semi) revolução de duas linhas não paralelas ao redor de um eixo que passa pela interseção e perpendicular à linha bissetriz; A projeção em um plano 2D é igual ao cone duplo, mas o eixo de rotação é perpendicular ao que gera o cone.
** É improvável que essa trajetória seja circular, elíptica ou até fechada. As chances são de que a trajetória siga um caminho parecido com um espirógrafo (um hipotrocóide) em 2D ou mesmo em outros monstros em 3 ou mais dimensões. Você não pode alcançar o centro de tais curvas de qualquer maneira e elas se parecem com círculos de uma trajetória "circular".
fonte
Seu sistema de orientação é construído com base no pressuposto de que a aceleração direta em direção ao alvo fará com que os objetos colidam. Uma vez que essa suposição é falsa, a orientação AI baseada nessa suposição também é malsucedida.
Então pare de acelerar diretamente em direção ao alvo. Adicione alguma lógica para detectar se a posição do alvo é um pouco perpendicular à direção do movimento do míssil. Nesse caso, o míssil precisa acelerar em direção ao alvo, mas também desacelerar o movimento para frente. Portanto, ao invés de ir diretamente em direção ao alvo, ele distorce a direção de sua aceleração, para que a velocidade atual em sua direção de movimento seja mais lenta.
Além disso, você precisará de um gatilho para se certificar de que não está indo muito devagar. Portanto, adicione uma velocidade de limite que, se você estiver abaixo desse limite, pare de fazer a polarização.
Uma última coisa: nenhum sistema de orientação será perfeito. A razão pela qual os mísseis podem interceptar alvos na vida real é que os alvos se movem muito mais lentamente do que os próprios mísseis, e os alvos não são particularmente ágeis (relativamente falando). Se seus mísseis não forem muitas vezes mais rápidos do que os alvos que perseguem, eles perderão muito.
fonte
O método mais simples e avançado a ser usado em jogos (e na vida real) é a Navegação proporcional.
Sob o rolamento constante Diminuindo Faixa lógica (CBDR), quando dois objetos (de mísseis e de destino) está viajando na mesma direção, sem mudança na linha de visão entre si, eles vão colidir.
Linha de Visão, ou Linha de Visão (LOS) é uma linha imaginária entre o míssil e o alvo - o vetor entre a posição do míssil e a posição do alvo. A taxa de alteração angular deste LOS é a taxa de rotação do LOS.
Quando a taxa de rotação do LOS se torna zero, a linha de visão não muda mais - os dois objetos estão agora em rota de colisão. Pense em si mesmo como perseguindo alguém enquanto joga futebol. Se você o liderar de uma maneira que o corpo dele pareça "congelado" no seu campo de visão (a linha de visão entre você e ele não muda mais), você colidirá com ele desde que mantenha a aceleração da corrida para manter o corpo dele congelado. sua visão.
Sob Navegação Proporcional (PN), o míssil acelera "N" vezes mais rápido que a Taxa de Rotação LOS. Isso forçará o míssil a liderar o alvo até que a taxa de rotação LOS se torne zero - ou seja, o míssil e o alvo pareçam congelados no estado, já que a linha de visão não muda mais - eles estão agora em rota de colisão. A variável "N" é conhecida como constante de navegação (um multiplicador constante).
O comando de orientação do míssil deve ser o seguinte:
Aceleração = velocidade de fechamento * N * taxa LOS
A taxa de LOS pode ser facilmente calculada medindo o vetor LOS (posição de destino - posição de míssil) e armazenando sua variável. O vetor LOS do novo quadro (LOS1) é subtraído pelo vetor LOS do quadro antigo (LOS0) para gerar um delta de LOS - agora você tem uma taxa de rotação LOS primitiva.
Para simplificar a velocidade de fechamento, você pode apenas usar o vetor LOS atual em seu lugar, assim:
Aceleração = (target_pos - missile_pos) * LOS_delta * N
N é a constante de navegação - no mundo real, geralmente é definida entre 3 e 5, mas o valor real praticável no jogo depende um pouco da taxa de amostragem na qual você está derivando a taxa / delta de LOS. Tente um número aleatório (comece de 3) e aumente até 1500, 2000, etc. até ver o efeito principal desejado no jogo. Observe que quanto maior a constante de navegação, mais rápido o míssil reagirá às alterações da taxa de LOS no início do voo. Se o seu modelo de simulação de foguete é realmente realista, uma constante navegação excessiva pode sobrecarregar a capacidade aerodinâmica do seu míssil, então você deve usar um número balanceado com base em tentativa e erro.
fonte
Como as outras respostas de Martin e Nicol apontam, você provavelmente deseja guiar seu míssil não diretamente no alvo, mas de uma maneira que o faça colidir com o alvo mais tarde. No entanto, o método descrito por Martin é complicado e o descrito por Nicol é ineficiente.
Uma maneira mais simples - mas ainda bastante eficiente - de guiar um míssil é ajustando seu ângulo de acordo com a mudança de ângulo entre o míssil e o alvo. Em cada escala, você calcula o ângulo do míssil para o alvo e o compara com o ângulo da escala anterior. A diferença é a diferença exata que você deseja fazer no ângulo do míssil. Portanto, se o ângulo era 0,77 em um tick e 0,75 no próximo, você deseja ajustar o ângulo do míssil em -0,02. Este método é simples e, desde que o alvo esteja "na frente" do míssil, é muito eficiente em termos de rota escolhida. Também se aplica a qualquer número de dimensões, não apenas em 2D.
Lembre-se, porém:
Esse método é interrompido se o míssil e o alvo estiverem exatamente na mesma velocidade e viajarem paralelamente. Bem, teoricamente ainda traça uma rota de colisão para o míssil, leva apenas um tempo infinito :) na prática, o míssil deve ser sempre mais rápido que o alvo, mas se eles tiverem velocidade idêntica, você precisará adicionar uma caixa de esquina para identificar se são paralelos .
O método é interrompido se o alvo e o míssil estiverem voando exatamente na mesma linha, mas em direções opostas. Isso realmente não pode acontecer no mundo real, mas não é incomum em um jogo discreto. Você precisa adicionar uma verificação de maiúscula ao algoritmo acima para testar isso.
Se o seu míssil tiver capacidade limitada de giro, basta fazer o giro máximo toda vez que precisar girar mais do que isso. Enquanto o míssil estiver longe o suficiente, ele ainda funcionará. Se estiver muito perto, veja a última bala.
Lembre-se de ser indulgente ao verificar colisão. No mundo real, muitos mísseis confiam em sua ogiva para produzir uma "zona de matança"; portanto, eles só precisam se aproximar do alvo e não colidir com ele.
Finalmente, na prática, o míssil ainda pode errar , o que nos leva de volta à sua pergunta original. Eu acho que uma boa maneira é realmente desabilitar a homing por alguns ticks, deixando-a alcançar alguma distância e depois torná-la novamente. Eu acho que o método proposto pelo fxiii para identificar zonas mortas é uma ótima maneira de detectar quando você precisa desativar o retorno.
fonte
Algumas opções simples que foram consideradas 'boas o suficiente' para jogos nos quais trabalhei no passado:
1) Se a resolução da cena que você está vendo permitir, o objeto poderá explodir quando estiver próximo do alvo (que é como eu acredito que os mísseis homing comuns do dia-a-dia realmente funcionam em qualquer caso). Se o seu alcance de órbita tiver aproximadamente o dobro do tamanho do objeto, isso provavelmente não funcionará para você, pois acabaria ficando mal.
Se o seu objetivo final na sua solução é simplesmente garantir que seu míssil atinja o alvo, eu sou a favor apenas de fazê-lo atingir o alvo. Novamente, isso dependerá apenas da aparência da solução.
2) Se você achar que seu míssil está em ângulo reto com seu alvo, esse pode ser o ponto em que a trava 'quebra' e o míssil se move em linha reta, a menos que o alvo fique 'na frente' do míssil novamente.
Eu sempre prefiro soluções simples sempre que possível. Se você está fazendo um jogo em que o míssil é apenas uma das armas que estão sendo usadas, é provável que você se safe disso, pois os jogadores provavelmente dispararão uma salva e depois voltarão a suas armas de envolvimento constante o mais rápido possível. No entanto, se você estiver fazendo uma simulação de míssil, então claramente uma das outras respostas é a melhor escolha.
Espero que isto ajude.
fonte
Como já foi dito, você deve apontar o míssil para onde o alvo deve estar quando chegar lá, e não para onde o alvo está agora. Isso impedirá que a maioria dos mísseis entre em órbita, mas uma órbita ainda é possível se o alvo fugir da maneira certa. Essa é uma tática legítima usada pelos pilotos de aeronaves para desviar dos mísseis que chegam - já que o míssil está indo muito mais rápido do que você, ele terá um raio de viragem maior e um jink afiado no instante certo o fará continuar. (Embora você ainda possa estar em risco de uma detonação de proximidade.)
Como estamos lidando com um míssil que ainda pode rastrear e ainda impulsionou, você terá uma situação em órbita se o alvo fugir para uma das zonas mencionadas no post de FxIII.
No entanto, eu discordo de sua solução para o problema. Em vez disso, eu programaria os mísseis da seguinte maneira:
se o míssil foi empurrado a 90 graus para sua linha de movimento por 360 graus de movimento, você está em órbita. Ajuste o impulso para 120 graus a partir da linha de movimento. A órbita do míssil aumentará, pois não está se tornando tão difícil, mas o míssil também diminuirá, permitindo manobras melhores. Quando o alcance do alvo atinge 1,25x o diâmetro da zona morta (observe que esse diâmetro é baseado simplesmente e apenas na velocidade do míssil, nenhum cálculo complexo é necessário em tempo de execução) o míssil retorna ao seu comportamento normal de rastreamento.
Como alternativa, use cabeças mais caçadoras - quando o intervalo a atingir deixa de contar, você detona.
fonte
Sei que essa é uma pergunta antiga, mas acho que há algo que foi esquecido nas respostas dadas até agora. Na pergunta original, o míssil (ou o que fosse) foi instruído a acelerar em direção à posição do alvo. Várias respostas apontaram que isso estava errado, e você deve acelerar para onde acha que o alvo estará em algum momento posterior. Isso é melhor, mas ainda está errado.
O que você realmente deseja fazer não é acelerar em direção ao alvo, mas avançar em direção ao alvo. A maneira de pensar sobre isso é definir a velocidade desejada apontada para o alvo (ou uma projeção da localização dos alvos) e, em seguida, descobrir qual aceleração você poderia aplicar melhor (dadas as restrições que tiver, por exemplo, um míssil provavelmente não pode ser acelerado). diretamente no sentido inverso) para atingir a velocidade desejada (lembrando que a velocidade é um vetor).
Aqui está um exemplo que eu implementei esta manhã, no meu caso de uma IA de jogador em um jogo de simulação de esportes, onde o jogador está tentando perseguir seu oponente. O movimento é governado por um modelo padrão de 'kick-drift', no qual as acelerações são aplicadas no início de um timestep para atualizar as velocidades e, em seguida, os objetos derivam nessa velocidade durante o timestap.
Eu publicaria a derivação disso, mas descobri que não há marcação matemática suportada neste site. Vaia! Você apenas terá que confiar que esta é a solução ideal, considerando que eu não tenho restrições na direção da aceleração, o que não é o caso de um objeto do tipo míssil, de modo que exigiria algumas restrições extras.
O código está em python, mas deve ser legível em qualquer fundo da linguagem. Por uma questão de simplicidade, presumo que cada etapa do tempo tem um comprimento de 1 e expresso a velocidade e a aceleração em unidades apropriadas para refletir isso.
Observe que a função atan2 (a, b) calcula o tan inverso de a / b, mas garante que os ângulos fiquem no quadrante correto de um círculo, o que requer conhecer o sinal de a e b.
No meu caso, uma vez que tenho a aceleração, aplico isso para atualizar a velocidade
Eu também verifico a nova velocidade em relação à velocidade máxima dependente de um jogador e a limito a isso. No caso de um míssil, carro ou algo com uma taxa de giro máxima (em graus por tick), você pode simplesmente olhar o ângulo de movimento atual versus o ideal calculado e, se essa alteração for maior do que o permitido, basta alterar o ângulo da seguinte maneira: tanto quanto possível em direção ao ideal.
Para qualquer pessoa interessada na derivação disso, anotei a distância entre o jogador e o alvo após o passo do tempo, em termos de posição inicial, velocidade, taxa de aceleração e ângulo de aceleração, e depois tomei a derivada em relação ao ângulo de aceleração. Definir esse valor como zero encontra os mínimos da distância entre o jogador e o alvo após o timestep em função do ângulo de aceleração, que é exatamente o que queremos saber. Curiosamente, embora a taxa de aceleração estivesse originalmente nas equações, ela cancela, tornando a direção ideal independente de quanto você é capaz de acelerar.
fonte
Você está usando uma taxa de turno constante. É exatamente isso que está causando a bela órbita perfeitamente circular.
Uma abordagem mais realista para um sistema de orientação seria variar a taxa de rotação com a distância inversamente desejada (menor distância -> mais taxa de rotação). Isso daria uma espiral ao invés de orbitar e garantiria a colisão com um alvo mais lento.
Também oferece uma trajetória de vôo muito mais realista. A taxa de giro constante é artificialmente perfeita. Você também pode adicionar variações aleatórias à taxa de rotação para simular turbulência. Novamente, muito mais realista e pode realmente evitar cenários de órbita em estado estacionário.
Não há necessidade de equações parciais.
fonte