Estou fazendo uma IA rudimentar para o meu side-scroller e preciso saber se uma unidade de IA pode alcançar o ponto B a partir do ponto A simplesmente dando um pulo.
A trajetória de vôo dos meus personagens é um pouco incomum, pois eles podem aplicar força no ar (como no Jazz Jackrabbit 2, por exemplo), tão diferente da trajetória clássica de um projétil que é sobre ...
caminho que um projétil lançado ou lançado seguirá (...) sem propulsão.
... Suponho que meu problema seja mais sobre um projétil com propulsão (por exemplo, foguete).
Para ilustrar isso, é assim que a curva de vôo se parece com o meu personagem se eu pular e pressionar continuamente o "botão esquerdo" (parece diferente no lado esquerdo, é aqui que eu estava fazendo algumas manobras no ar):
A força aplicada durante o vôo é sempre paralela ao eixo X, então é F = (-f, 0) se eu segurar "esquerda" e é F = (f, 0) se eu segurar "direita".
Ele pode se mover muito como um saltador de esqui:
Por isso, difere muito da trajetória clássica que é simplesmente uma parábola (fonte: wikipedia ):
Para tornar mais difícil, estou simulando uma resistência simples ao ar para que meus personagens possam acelerar apenas até algum valor de velocidade máxima.
Isso é feito aplicando uma pequena força na direção oposta da viagem :
b2Vec2 vel = body->GetLinearVelocity();
float speed = vel.Normalize(); //normalizes vector and returns length
body->ApplyForce( AIR_RESISTANCE_MULT * speed * speed * -vel, body->GetWorldCenter() );
O AIR_RESISTANCE_MULT é uma constante que, no meu caso, é igual a 0,1.
Vamos supor que meu personagem seja um ponto infinitamente pequeno.
E NÃO estou levando em consideração os obstáculos, então minha pergunta é assim ...
Como determinar (pelo menos adivinhar com confiabilidade), dada a velocidade inicial V, um impulso J = (0, -j) que aplico ao personagem ao pular, gravidade G = (0, g) , força F = (+ -f , 0) é aplicado continuamente durante o vôo e AIR_RESISTANCE_MULT se realmente decidirmos levar em consideração a resistência do ar (isso é opcional) , se um ponto está abaixo da curva traçada pelo caminho que meu personagem seguirá?
Não tenho literalmente idéia de por onde começar com os cálculos e, de fato, não estou necessariamente interessado em uma resposta exata; um hack / aproximação que funcione bem seria ótimo, pois a IA nunca precisa funcionar perfeitamente.
edit: Eu decidi resolver isso usando simulação, como Jason sugere, mas como lidar com esse caso?
Devo desenhar um segmento de C a D e verificar se o ponto desejado está abaixo desse segmento?
Ou devo procurar binário os timestados entre C e D para procurar o ponto que está suficientemente próximo na distância horizontal do ponto desejado e só então verificar a diferença vertical? (parece um pouco exagerado para mim)
fonte
Respostas:
Conforme você declara, a melhor opção é aproximar, neste caso usando um esquema numérico. Divida o tempo em grandes intervalos de tempo (digamos 100-300ms) e use a aproximação parabólica para cada intervalo de tempo. As forças são as mesmas, exceto a resistência do ar. O caminho parabólico é basicamente para aceleração constante, mas com a resistência do ar, a aceleração muda porque a força depende da velocidade. Uma aproximação razoável é tratar a resistência do ar como constante a cada passo do tempo. Mas usar uma aproximação quadrática (isto é, parabólica) ao integrar permite lidar com timestados muito maiores. Então você apenas calcula até que uma parábola cruze o ponto desejado na direção horizontal e, em seguida, compare as alturas.
EDIT: Um pouco mais de detalhes sobre a comparação. Você sabe que ao longo do tempo (que pode ser grande parte dos quadros de jogo), o jogador cruza o alvo
<targetx,targety>
. Seu caminho é descrito pela posição em<ax*t^2 + bx*t + cx, ay*t^2 + by*t + cy>
que:t
é o tempo no timestep (0 <= t <= dt
) e da mesma forma paray
. Então, quandot=0
o personagem está na posição anterior e quandot=dt
, ele está na próxima posição. Observe que esta é basicamente a atualização de Eulerdt
substituída por,t
para que possamos calcular em qualquer lugar ao longo da trajetória. Agora sabemos que a posição x é uma função quadrática, para que possamos resolverax*t^2 + bx*t + cx = targetx
e obter (até) duas vezes durante a etapa em que o personagem está diretamente acima ou abaixo do alvo. Em seguida, descartamos quaisquer soluções que não estejam no intervalo [0,dt
], pois esses não estão no timestep atual. (Para maior robustez, adicione uma pequena constante às extremidades do intervalo para não ter problemas de arredondamento). Agora, não poderíamos ter soluções (após a filtragem), caso em que não atingimos o alvo neste passo de tempo. Caso contrário, avaliamosay*t^2 + by*t + cy
as soluções e comparamos isso comtargety
. Observe que você pode estar acima do alvo em um ponto da sua trajetória e abaixo dele mais tarde (ou vice-versa). Você precisará interpretar essas situações de acordo com o que deseja fazer.Considerar vários passos de tempo é muito mais fácil do que encontrar uma solução analítica para o problema original e muito mais flexível, pois você pode alterar o modelo de movimento e isso ainda funcionará aproximadamente.
Pontos de bônus por usar etapas variáveis, por exemplo, 100ms no primeiro segundo (dez pontos), 200ms nos próximos dois (dez mais pontos), 400ms em 4 segundos, etc. De fato, conforme seu personagem se aproxima da velocidade terminal, a variação em a resistência diminui e, de qualquer maneira, você não precisa de intervalos maiores. Dessa forma, você pode lidar com saltos muito longos sem muito processamento, pois a complexidade por T segundos é O (log T) em vez de O (T).
Você também pode simular o que acontece quando o personagem para de aumentar no meio do salto ou começa a aumentar de outra maneira. Com o truque acima, a complexidade é O ((log T) ^ 2), o que não é muito ruim.
fonte
x'= x + v*dt
. Em vez disso, usex' = x + v*dt + 1/2*a*dt*dt
. Quandodt
pequeno,dt^2
pequeno, geralmente é deixado de fora na integração tradicional do Euler nos jogos. Aquidt
não é pequeno, então você precisa do termo de aceleração. Comodt
é elevado à segunda potência, essa é uma integração quadrática, e o caminho é uma parábola, portanto, uma aproximação parabólica. O RK4 calcula essencialmente derivadas mais altas e, portanto, pode fornecer aproximações cúbicas, quárticas, quinticas etc. O RK4 é um exagero para isso, provavelmente, pois a estabilidade não é importante.v' = v + a*dt
Yay! Eu fiz isso!
Estou usando uma simulação simples que leva a primeira posição para pousar atrás do eixo vertical do ponto de destino - a partir daí, pego a posição simulada anterior e faço um segmento. Agora, verifico se o ponto de destino está abaixo desse segmento. Se for - podemos pular lá.
É um personagem controlado pelo jogador no gif. O rosa é o caminho previsto, os segmentos amarelos são as posições subseqüentes previstas e o segmento final fica branco se o ponto de destino estiver abaixo dele, vermelho caso contrário. Curva vermelha é a rota de vôo real. Há algumas pequenas imprecisões devido a interpolação Física do Estado ligado.
Os cálculos foram surpreendentemente fáceis, no entanto, fazer meu ambiente funcionar da mesma maneira que esses cálculos puros ... foi uma dor enorme no traseiro. Pelo menos eu resolvi alguns erros graves por aí, então foi um exercício útil, afinal.
Aqui está o código completo em Lua usado para resolver o problema original (o código pressupõe que você tenha sua própria rotina "debug_draw" e sua própria classe de vetor com métodos básicos como "length_sq" (length ao quadrado), "normalize" ou operadores +, * :
Accept vai até Jason por me colocar na direção certa! Obrigado!
fonte
Você pode "apenas calcular" a resposta, mas tenho certeza de que a achará insuficiente assim que a tiver, devido à natureza altamente interativa da sua física de "queda livre".
Considere usar uma abordagem diferente: Pesquisando. Aqui está como é feito o Super Mario AI: http://aigamedev.com/open/interview/mario-ai/
A busca de possíveis caminhos para ir de A a B permite interatividade ilimitada no ar enquanto ainda é computacionalmente eficiente.
fonte