Pergunta

Estou implementando um jogo 2D com naves no espaço.

Para fazer isso estou usando LÖVE, que envolve Box2D com Lua.Mas acredito que minha pergunta possa ser respondida por qualquer pessoa com maior conhecimento de física do que eu - portanto, o pseudocódigo é aceito como resposta.

Meu problema é que não sei como mover minhas naves espaciais adequadamente em um mundo 2D habilitado para física.Mais concretamente:

Um navio de massa m está localizado em uma posição inicial {x, y}.Tem um vetor velocidade inicial de {vx, vy} (pode ser {0,0}).

O objetivo é um ponto {xo,yo}.O navio deve atingir o objetivo com uma velocidade de {vxo, vyo} (ou perto dele), seguindo a trajetória mais curta.

Existe uma função chamada update(dt) que é chamado com frequência (ou seja,30 vezes por segundo).Nesta função, o navio pode modificar sua posição e trajetória, aplicando “impulsos” a si mesmo.A magnitude dos impulsos é binária:você pode aplicá-lo em uma determinada direção ou não aplicá-lo).No código, fica assim:

function Ship:update(dt)
  m = self:getMass()
  x,y = self:getPosition()
  vx,vy = self:getLinearVelocity()
  xo,yo = self:getTargetPosition()
  vxo,vyo = self:getTargetVelocity()
  thrust = self:getThrust()

  if(???)
    angle = ???
    self:applyImpulse(math.sin(angle)*thrust, math.cos(angle)*thrust))
  end
end

O primeiro ??? está aí para indicar que em algumas ocasiões (eu acho) seria melhor “não impulsionar” e deixar o navio “à deriva”.O segundo ??? parte consiste em como calcular o ângulo de impulso em um determinado dt.

Estamos no espaço, então podemos ignorar coisas como o atrito do ar.

Embora fosse muito bom, não estou procurando alguém para codificar isso para mim;Coloquei o código lá para que meu problema seja claramente compreendido.

O que preciso é de uma estratégia – uma forma de atacar isto.Conheço um pouco de física básica, mas não sou especialista.Por exemplo, esse problema tem nome?Esse tipo de coisas.

Muito obrigado.

EDITAR:O Beta forneceu uma estratégia válida para isso e o Judge gentilmente a implementou diretamente no LÖVE, nos comentários.

EDITAR2:Depois de pesquisar mais no Google, também encontrei openSteer.Está em C++, mas faz o que eu fingi.Provavelmente será útil para qualquer pessoa que chegue a esta questão.

Foi útil?

Solução

É chamado de planejamento de movimento, e não é trivial.

Aqui está uma maneira simples de obter uma trajetória não ideal:

  1. Pare. Aplique o impulso oposto à direção da velocidade até que a velocidade seja zero.
  2. Calcule a última perna, que será o oposto do primeiro, um impulso constante de um começo em pé que leva o navio para X0 e V0. O ponto de partida estará a uma distância de | v0 |^2/(2*impulso) de x0.
  3. Chegue a esse ponto de partida (e depois faça a última perna). É fácil ir de um ponto de pé para outro: empurre -o até o meio do caminho e depois empurre para trás até parar.

Se você deseja uma abordagem rápida e suja de uma trajetória ideal, pode usar uma abordagem iterativa: comece com a abordagem não ideal, acima; Essa é apenas uma sequência de tempo de ângulos de impulso. Agora tente fazer pequenas variações dessa sequência, mantendo uma população de seqüências que se aproximam do objetivo. Rejeite o pior, experimente o melhor - se você estiver se sentindo ousado, pode fazer disso um algoritmo genético - e com sorte começará a arredondar os cantos.

Se você deseja a resposta exata, use o cálculo das variações. Vou fazer uma rachadura nisso, e se for bem -sucedido, postarei a resposta aqui.

EDITAR: Aqui está a solução exata para um problema mais simples.

Suponha que, em vez de um impulso que possamos apontar em qualquer direção, tenhamos quatro propulsores fixos apontando nas direções { +x, +y, -x, -y}. A qualquer momento, dispararemos no máximo um dos +/- x e no máximo um dos +/- y (não há sentido em disparar +x e -x ao mesmo tempo). Então agora os problemas X e Y são independentes (eles não estão no problema original porque o impulso deve ser compartilhado entre x e y). Agora devemos resolver o problema 1-D-e aplicá-lo duas vezes.

Acontece que a melhor trajetória envolve empurrar em uma direção, depois a outra, e não voltar ao primeiro. (O litoral é útil apenas se a solução do outro eixo levar mais tempo que a sua, para que você tenha tempo para matar.) Resolva o problema da velocidade primeiro: suponha (wlog) que sua velocidade alvo seja maior que a velocidade inicial. Para atingir a velocidade alvo, você precisará de um período de impulso (+) de duração

T = (Vf - Vi)/a

(Estou usando VF: velocidade final, vi: velocidade inicial, a: magnitude do impulso.)

Percebemos que, se isso é tudo o que fazemos, o local não sairá certo. A localização final real será

X = (Vi + Vf)T/2

Então, temos que adicionar uma correção de

D = Xf - X = Xf -(Vi+Vf)T/2

Agora, para fazer a localização sair corretamente, adicionamos um período de impulso em uma direção antes da isso, e um período igual na direção oposta depois. Isso deixará a velocidade final imperturbável, mas nos dará algum deslocamento. Se a duração deste primeiro período (e o terceiro) for t, o deslocamento que obtemos é

d = +/-(at^2 + atT)

O +/- depende se empurramos +então - ou - então +. Suponha que seja +. Nós resolvemos o quadrático:

t = (-aT + sqrt(a^2 T^2 + 4 a D))/2a

E terminamos.

Outras dicas

Na ausência de informações adicionais, podemos assumir que existem 3 forças agindo sobre a nave espacial e eventualmente ditando a sua trajetória:

  • "impulsos":força [controlada pelo usuário/programa].
    O usuário (ou programa) parece ter controle total sobre isso, ou seja,controla a direção do impulso e seu impulso (provavelmente dentro de uma faixa de 0 ao máximo)
  • alguma força externa:chame isso de gravidade, tanto faz...
    Essa força poderia ser impulsionada por diversas fontes, mas estamos interessados ​​apenas na força combinada resultante:num determinado tempo e espaço, esta força externa atua sobre o navio com uma determinada força e direção.O usuário/programa não tem controle sobre eles.
  • inércia:isso está relacionado à velocidade e direção atuais do navio.Essa força geralmente faz com que o navio continue na direção atual na velocidade atual.Pode haver outros parâmetros [da era espacial] controlando a inércia, mas geralmente ela é proporcional à velocidade e à massa da nave (intuitivamente, será mais fácil parar uma nave se sua velocidade atual for menor e/ou se sua massa for menor)

Aparentemente o usuário/programa controla apenas (dentro dos limites) a primeira força.
Não está claro, a partir da pergunta, se o problema em questão é:

  • [Problema A] para escrever um programa que descubra a dinâmica do sistema (e/ou se adapte às mudanças nesta dinâmica).
    ou..
  • [Problema B] para sugerir um modelo -uma fórmula- que pode ser usada para calcular a força combinada eventualmente aplicada ao navio:a soma "ponderada" do impulso controlado pelo usuário e as outras duas forças acionadas pelo sistema/física.

A última questão, Problema B, é explicada de forma mais rápida e sucinta, então vamos sugerir o seguinte modelo:

Constant Parameters:
  ExternalForceX   = strength of the external force in the X direction
  ExternalForceY   = id. Y direction
  MassOfShip       = coeficient controlling 
Variable Parameters:
  ImpulseAngle     = direction of impulse
  ImpulseThrust    = force of thrust
Formula:
  Vx[new] = (cos(ImpulseAngle) * ImpulseThrust) + ExternalForceX  + (MassOfShip * Vx[current])
  Vy[new] = (sin(ImpulseAngle) * ImpulseThrust) + ExternalForceY  + (MassOfShip * Vy[current])

Observe que o modelo acima assume uma força externa constante (constante tanto em termos de força quanto de direção);aquilo é:semelhante ao de um campo gravitacional relativamente distante da área exibida (exatamente como, digamos, a gravidade da Terra, considerada dentro da extensão de um campo de futebol).Se a escala da área exibida for grande em relação à(s) fonte(s) de forças externas, o termo médio das fórmulas acima deverá então ser modificado para incluir:um fator trigonométrico baseado no ângulo entre o centro da fonte e a posição atual e/ou um fator [inversamente] proporcional baseado na distância entre o centro da fonte e a posição atual.
Da mesma forma, presume-se que a massa do navio permaneça constante, podendo muito bem ser uma variável, baseada, digamos, na massa do navio quando vazio, à qual o peso do combustível é removido/adicionado à medida que o jogo avança.

Agora...Todos os itens acima assumem que a dinâmica do sistema é controlada pelo designer do jogo:essencialmente escolhendo um conjunto de valores para o parâmetro mencionado e possivelmente adicionando um pouco de complexidade na matemática da fórmula (e também garantindo o dimensionamento adequado para geralmente "manter" o navio dentro da área de exibição).

E se, em vez disso, a dinâmica do sistema fosse prontamente programada no jogo (e assumida como oculta/aleatória), e a tarefa em questão fosse escrever um programa que decidirá progressivamente a direção e o valor do empuxo dos impulsos para conduzir a nave para seu destino alvo, de forma que sua velocidade no alvo seja o mais próximo possível de getTargetVelocity()?Este é o “Problema A”.

Este tipo de problema pode ser resolvido com uma Controlador PID.Em suma, tal controlador "decide" qual quantidade de ação (no caso deste jogo = qual ângulo de impulso e quantidade de impulso aplicar), com base em três fatores ponderados, vagamente definidos abaixo:

  • quão distantes estamos dos valores atuais do "ponto de ajuste":esta é a parte P=Proporcional do PID
  • com que rapidez estamos nos aproximando do "ponto de ajuste":esta é a parte D = Derivada do PID
  • há quanto tempo e quanto estivemos longe do "ponto definido":esta é a parte I = Integral do PID

Um controlador menos sofisticado poderia, por exemplo, utilizar apenas o fator proporcional.Isso resultaria em oscilação, às vezes com muita amplitude em ambos os lados do ponto de ajuste ("Estou a X unidades de distância de onde deveria estar:deixe-me puxar o volante e pisar no acelerador").Essa ultrapassagem do ponto de ajuste é atenuada pelo fator Derivativo ("Sim, ainda não estou onde deveria estar, mas o progresso que fiz desde a última vez que verifiquei é muito grande:é melhor desacelerar um pouco").Finalmente, a parte Integral leva em consideração o fato de que sendo todas as coisas iguais em relação à parte Proporcional e Derivada combinadas, uma ação menor ou maior seria apropriada dependendo se estivemos "fora do caminho" por um longo tempo ou não e de muita coisa que estivemos fora do caminho todo esse tempo (ex."Ultimamente temos rastreado bem perto de onde deveríamos estar, não adianta fazer movimentos precipitados")

Podemos discutir os detalhes da implementação de controladores PID para as necessidades específicas do jogo de nave espacial, se isso for efetivamente necessário.A ideia era dar uma ideia do que pode ser feito.

Para ir da posição atual para o destino com uma velocidade inicial, aplique impulso ao longo da diferença normalizada entre o caminho mais curto e a velocidade atual. Você realmente não precisa do ângulo.

-- shortest path minus initial velocity
dx,dy = x0 - x - vx, y0 - y - vy

-- normalize the direction vector
magnitude = sqrt(dx*dx + dy*dy)
dx,dy = dx/magnitude, dy/mangitude

-- apply the thrust in the direction we just calculated
self:applyImpulse(thrust*dx, thrust*dy)

Observe que isso não leva em consideração a velocidade alvo, porque isso fica extremamente complicado.

Eu tenho um módulo Lua muito pequeno para lidar com vetores 2D Esta lixeira. Você pode usá -lo. O código acima reduziria para:

d = destination - position - velocity
d:normalize()
d = d * thrust
self:applyImpulse(d.x, d.y)

Eu acho que o assunto é o seu motor de mesas.Eu acho que você está usando o InnoDB para a sua mesa.Então você não pode copiar arquivos facilmente para fazer uma cópia.
Dê uma olhada nesses links:
http://dev.mysql.com/doc/refman/5.0/en/innodb-backup.html
http://dev.mysql.com/doc/refman/5.0/en/innodb-migration.html

Também eu recomendo que você use algo como phpmyadmin para criar seu arquivo de backup e restaurar o arquivo de backup na próxima máquina usando o mesmo IDE.

É mais fácil pensar se você separar a velocidade do navio em componentes, paralelo e perpendicular para o vetor de velocidade alvo.

Considerando ao longo do eixo perpendicular, o navio quer chegar alinhado com a posição alvo o mais rápido possível e depois ficar lá.

Ao longo do eixo paralelo, ele deve estar acelerando em qualquer direção que o aproxime da velocidade alvo. (Obviamente se essa aceleração o levar um jeito Do ponto de destino, você precisará decidir o que fazer. Voar além do ponto e depois dupla?)

Eu lidaria com os dois separadamente e provavelmente perpendicularmente primeiro. Uma vez que está funcionando, e se isso não for bom o suficiente, você pode começar a pensar se houver maneiras de fazer com que o navio dispare ângulos inteligentes entre perpendicular e paralelo.

(Editar: Além disso, esqueci de mencionar, isso levará algum ajuste para lidar com o cenário em que você está compensado muito na direção perpendicular, mas não muito na direção paralela. A lição importante aqui é levar os componentes, o que dá seus números úteis nos quais basear uma decisão.)

Seu ângulo é a tangente inversa do oposto/adjacente

Então ângulo = InvTan (VY/VX)

Não tenho certeza do que você está falando sobre querer desviar?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top