Como posso interceptar objetos com um movimento circular

23

Estou criando um jogo espacial 2D e preciso fazer a nave interceptar um planeta. Eu tenho código de trabalho para interceptações em linha reta, mas não consigo descobrir como calcular a localização dos planetas em uma órbita circular.

O jogo não é cientificamente preciso, então não estou preocupado com inércia, gravidade, órbitas elípticas, etc.

Eu sei a localização e velocidade das naves espaciais e também os planetas orbitam (Radius) e a velocidade

insira a descrição da imagem aqui

Ausa
fonte
11
Não, estou tentando calcular o ângulo que a nave precisa se mover para interceptar o planeta.
Ausa 14/05
4
Isso provavelmente funcionaria melhor em math.stackexchange.com ..
Jari Komppa
2
O seu navio é capaz de mudar de velocidade e direção ou são constantes? Além disso, essa pergunta sobre como evitar que mísseis circulem um alvo pode ser útil.
thegrinner
4
Para esclarecer, é a situação? dados para o planeta: centro da órbita, raio da órbita, velocidade angular, localização atual; para o navio : localização atual, velocidade atual; determinar direção do movimento para o navio, a fim de interceptar planeta
AakashM
6
Como uma nota histórica interessante: os planetas geralmente giram na mesma direção que sua órbita, o que também é no sentido anti-horário, visto de cima do hemisfério norte. Deste fato, podemos deduzir que os relógios de sol foram inventados no hemisfério norte . Se os relógios de sol tivessem sido inventados no hemisfério sul, no sentido horário, seria o contrário .
Eric Lippert

Respostas:

3

Uma solução analítica para isso é difícil, mas podemos usar a pesquisa binária para encontrar uma solução com a precisão necessária.

A nave pode chegar ao ponto mais próximo da órbita no tempo t_min :

shipOrbitRadius = (ship.position - planet.orbitCenter).length;
shortestDistance = abs(shipOrbitRadius - planet.orbitRadius);
t_min = shortestDistance/ship.maxSpeed;

A nave pode atingir QUALQUER ponto da órbita em tempo menor ou igual a t_max :

(Aqui, por simplicidade, presumo que o navio possa dirigir pelo sol. Se você quiser evitar isso, precisará mudar para caminhos não lineares por pelo menos alguns casos. "Beijar círculos" pode parecer agradável e orbital mecânica-y, sem alterar o algoritmo por mais que um fator constante)

if(shipOrbitRadius > planet.orbitRadius)
{
   t_max = planet.orbitRadius * 2/ship.maxSpeed + t_min;
}
else
{
   t_max = planet.orbitRadius * 2/ship.maxSpeed - t_min;
}

Se nosso período orbital for curto, poderemos melhorar esse limite superior, escolhendo t_maxa primeira vez depois t_minque o planeta se aproximar mais da posição inicial da nave. Tome qualquer um desses dois valores t_maxmenor. Veja esta resposta posterior para obter uma derivação de por que isso funciona.

Agora podemos usar a pesquisa binária entre esses extremos, t_min e t_max . Procuraremos um valor t que obtenha o erro próximo de zero:

error = (planet.positionAtTime(t) - ship.position).squareMagnitude/(ship.maxSpeed*ship.maxSpeed) - t*t;

(Usando essa construção, erro @ t_min> = 0 e erro @ t_max <= 0, portanto, deve haver pelo menos uma interceptação com erro = 0 para um valor t intermediário)

onde, para completar, a função position é algo como ...

Vector2 Planet.positionAtTime(float t)
{
  angle = atan2(startPosition - orbitCenter) + t * orbitalSpeedInRadians;
  return new Vector2(cos(angle), sin(angle)) * orbitRadius + orbitCenter;
}

Observe que, se o período orbital do planeta for muito curto comparado à velocidade da nave, esta função de erro poderá alterar os sinais várias vezes ao longo do intervalo de t_min a t_max. Apenas acompanhe o par mais antigo de ve e -v que você encontrar e continue pesquisando entre eles até que o erro esteja próximo o suficiente de zero ("perto o suficiente" sendo sensível às suas unidades e ao contexto de jogo. O quadrado da metade da duração do quadro pode funciona bem - que garante que a interceptação seja precisa dentro de um quadro)

Depois de ter um bom t minimizador de erros, basta apontar a nave para planet.positionAtTime (t) e acelerar a toda velocidade, confiante de que o planeta alcançará esse ponto ao mesmo tempo que você.

Você sempre pode encontrar uma solução nas iterações Log_2 ((2 * orbitRadius / ship.maxSpeed) / errorThreshold). Por exemplo, se minha nave puder atravessar a órbita em 60 quadros e eu desejar uma interceptação precisa dentro de um quadro, precisarei de cerca de 6 iterações.

DMGregory
fonte
11
Muitas respostas boas aqui, também algumas opções alternativas interessantes, mas pelo que eu já tinha essas soluções parece melhor para a minha instância. Criei uma pequena demonstração JavaScript dos meus resultados. Demonstração
Ausa 15/05
11

Não vamos complicar demais isso. Esta não é uma solução "perfeita", mas deve funcionar para a maioria dos jogos e qualquer imperfeição deve ser invisível para o jogador.

if(!OldTargetPoint)
  TargetPoint = PlanetPosition;
else
  TargetPoint = OldTargetPoint;
Distance = CurPosition - TargetPoint;
TimeNeeded = Distance / Speed;
TargetPoint = PlanetPositionInFuture(TimeNeeded);
SteerTowards(TargetPoint);
[...repeat this every AI update, for example every second...]
  1. Calcule o tempo necessário para atingir o ponto alvo.
  2. Calcule em que posição o planeta estará no tempo calculado.
  3. Vá para o ponto calculado.
  4. Repetir

Isso funciona porque quanto mais próxima a espaçonave fica, mais baixo se torna o erro. Portanto, o cálculo se torna mais estável ao longo do tempo.

O erro é a diferença entre o tempo calculado necessário para alcançar o planeta (TimeNeeded) e o tempo real necessário para alcançar o planeta (depois de levar em consideração o novo TargetPoint).

API-Beast
fonte
11
Você pode executar duas iterações disso ao iniciar um curso de interceptação, caso contrário, poderá ver o navio piscar momentaneamente entre duas direções (a segunda suposição pode ser muito melhor que a primeira e resultar em um rumo muito diferente - principalmente se a nave está perto ou dentro da órbita do planeta)
DMGregory
11
@DMGregory Oh! Poderíamos apenas tomar a posição atual do planeta em vez do centro de órbita como ponto de partida. Quando estamos perto, está muito mais perto; se estamos longe, não importa.
API-Beast
Também vale a pena notar que isso funciona melhor quando o planeta se move lentamente em comparação com a nave. Se a velocidade do planeta for comparável ou superior à da nave, você poderá ver oscilações no caminho da nave. Em relações de velocidade patológicas, a nave pode perseguir o planeta para sempre em uma órbita concêntrica. Se seus planetas são rápidos e você percebe que isso está acontecendo, você pode planejar todo o curso de interceptação antecipadamente, em vez de iterar no meio do vôo.
DMGregory
3

Vamos começar dando uma olhada na matemática por trás do problema.

Passo 1:

Encontrar a interseção entre uma linha e uma forma é apenas uma questão de inserir a equação da linha na equação da forma, que neste caso é um círculo.

Linha que cruza com círculo

Faça um círculo com o centro ce raio r . Um ponto p está no círculo se

|pc|2=r2

Com uma linha expressa como p=p0+μv (onde v é um vetor, http://en.wikipedia.org/wiki/Euclidean_vector ), você insere a linha na fórmula do círculo e obtém

|p0+μvc|2=r2

A distância ao quadrado pode ser reescrita como um produto escalar ( http://en.wikipedia.org/wiki/Dot_product ).

(p0+μvc)(p0+μvc)=r2

a=cp0(μva)(μva)=r2

μ2(vv)2μ(av)+aa=r2

|v|=1

μ22μ(av)+|a|2r2=0

que é uma equação quadrática simples, e chegamos à solução

μ=av+sqrt((av)2a2r2)

μ<0

μ=0

μ

Passo 2:

μ

O que podemos fazer com isso? Bem, agora sabemos a distância que o navio deve percorrer e em que ponto ele terminará!

p=p0+μvμv

Agora, tudo o que resta fazer é calcular onde o planeta deve estar quando a nave começar a se aproximar de sua órbita. Isso é facilmente calculado com os chamados coodinatos polares ( http://mathworld.wolfram.com/PolarCoordinates.html )

x=c+rcos(θ)

y=c+rsin(θ)

tangularVelocity

Sumário

Escolha uma linha para sua nave e faça a matemática para ver se ela colide com a órbita dos planetas. Nesse caso, calcule o tempo necessário para chegar a esse ponto. Use esse tempo para voltar em órbita a partir deste ponto com o planeta para calcular onde o planeta deve estar quando a nave começar a se mover.

Tholle
fonte
8
Boa análise, mas não parece responder à pergunta (esclarecida em um comentário): "Não, estou tentando calcular o ângulo que a nave precisa se mover para interceptar o planeta". Você está considerando o ângulo da nave e calculando a posição do planeta, e não o contrário.
Chaosed0
4
Não vou votar isso porque é uma análise útil, mas eu concordo com o @ Chaosed0 que ele não responde à pergunta. No seu resumo, você diz "Escolha uma linha para o seu navio ...", mas escolher essa linha é exatamente a parte mais difícil.
Drake
1

Aqui estão duas soluções "prontas para uso".

A questão é: dado que a nave se move em uma linha reta a uma velocidade determinada, e o planeta se move em um círculo de raio determinado a uma velocidade angular determinada, e as posições iniciais do planeta e da nave, determinam qual direção o vetor da nave deve haver uma linha reta para traçar um percurso de interceptação

Solução 1: Negue a premissa da pergunta. A quantidade "deslizável" na pergunta é o ângulo. Em vez disso, conserte isso. Aponte o navio diretamente para o centro da órbita.

  • Calcule a posição em que a nave encontrará o planeta; isso é fácil.
  • Calcular a distância do navio até a posição de interceptação; também é fácil.
  • Calcule o tempo que levará até o próximo planeta atingir a posição de interceptação. Fácil.
  • Divida a distância da nave até a interceptação pelo tempo até o planeta chegar à interceptação.
  • Se isso for menor ou igual à velocidade máxima do navio, você está pronto. Defina o navio se movendo nessa velocidade diretamente em direção ao sol.
  • Caso contrário, adicione o período orbital do planeta à hora e tente novamente. Continue fazendo isso até obter uma velocidade dentro do motivo do navio.

Solução 2: Não faça isso no piloto automático. Faça um mini-jogo no qual o jogador precise usar propulsores para se aproximar do planeta e, se o atingirem em uma velocidade relativa muito alta, eles explodem, mas também têm combustível limitado. Faça o jogador aprender a resolver o problema de interceptação!

Eric Lippert
fonte
1

(x,y,t)

tv=x2+y2

v

A posição do planeta no espaço e no tempo pode ser parametrizada por

x=x0 0+rcos(Wvocê+uma)y=y0 0+rsEun(Wvocê+uma)t=você

Onde você vai de 0 0 para cima. W é a velocidade angular e uma is the starting angle of the planet at time zero. Then solve where the ship and planet could meet in time and space. You get an equation for u to solve:

uv=(x0+rcos(wu+a))2+(y0+rsin(wu+a))2u2v2=(x0+rcos(wu+a))2+(y0+rsin(wu+a))2u2v2=x02+y02+r2+2x0rcos(wu+a)+2y0rsin(wu+a)

This equation needs to be solved numerically. It may have many solutions. By eyeballing it, it seems it always has a solution

Toni Makkonen
fonte
1

Here's part of a solution. I didn't get to finish it in time. I'll try again later.

If I understand correctly, you have a planet's position & velocity, as well as a ship's position and speed. You want to get the ship's movement direction. I'm assuming the ship's and planet's speeds are constant. I also assume, without loss of generality, that the ship is at (0,0); to do this, subtract the ship's position from the planet's, and add the ship's position back onto the result of the operation described below.

Unfortunately, without latex, I can't format this answer very well, but we'll attempt to make do. Let:

  • s_s = the ship's speed (s_s.x, s_s.y, likewise)
  • s_a = the ship's bearing (angle of movement, what we want to calculate)
  • p_p = the planet's initial position, global coords
  • p_r = the planet's distance (radius) from the center of orbit, derivable from p_p
  • p_a = the planet's initial angle in radians, relative to the center of orbit
  • p_s = the planet's angular velocity (rad/sec)
  • t = the time to collision (this turns out to be something we must calculate as well)

Here's the equations for the position of the two bodies, broken down into components:

ship.x = s_s.x * t * cos(s_a)
ship.y = s_s.y * t * sin(s_a)

planet.x = p_r * cos(p_a + p_s * t) + p_p.x
planet.y = p_r * sin(p_a + p_s * t) + p_p.y

Since we want ship.x = planet.x and ship.y = planet.y at some instant t, we obtain this equation (the y case is nearly symmetrical):

   s_s.x * t * cos(s_a) = p_r * cos(p_a + p_s * t) + p_p.x
   s_s.y * t * sin(s_a) = p_r * sin(p_a + p_s * t) + p_p.y

Solving the top equation for s_a:

   s_s.x * t * cos(s_a) = p_r * cos(p_a + p_s * t) + p_p.x
=> s_a = arccos((p_r * cos(p_a + p_s * t) + p_p.x) / (s_s.x * t))

Substituting this into the second equation results in a fairly terrifying equation that Wolfram alpha won't solve for me. There may be a better way to do this not involving polar coordinates. If anyone wants to give this method a shot, you're welcome to it; I've made this a wiki. Otherwise, you may want to take this to the Math StackExchange.

Chaosed0
fonte
2
I would love to have TeX enabled for this site. It would make some graphics related stuff (e.g. vector, matrices, quaternions..) easier to represent.
mvw
0

I would fix the location at which to intercept (graze the circle, at the "outgoing" side of the orbit.)

Now you just have to adjust the spaceship's speed so that planet and ship reach that point at the same time.

Note that the rendez-vous could be after N more orbits, depending how far away the ship is, and how fast the planet is orbiting the star.

Pick the N that in time, comes nearest to the ship's journey duration at current speed.

Then speed up or slow down ship to match the timestamp for those N orbits exactly.

In all this, the actual course is already known! Just not the speed.

Bram
fonte
This could give unnecessarily long trips. Let's say we're positioned so that the planet is coming toward us and we can actually reach the "incoming" grazing point at the same time the planet does. If we're only looking at the "outgoing" grazing point, then we could end up spending half an extra half a year in transit!
DMGregory
True... depends on orbital speeds. But it also minimizes the delta-speed if you always graze at outgoing. At "incoming" you could burn up in the atmosphere, whereas in "outgoing" you are more likely to be matched. @DMGregory
Bram