Pregunta

Estoy implementando un juego en 2D con naves en el espacio.

Para hacerlo, estoy usando LÖVE, que se ajusta a Box2D con Lua.Pero creo que mi pregunta puede ser respondida por cualquier persona con una mayor comprensión de la física que a mí mismo - de modo pseudo código es aceptado como una respuesta.

Mi problema es que no sé cómo mover mis naves correctamente en 2D física habilitada mundo.Más concretamente:

Un buque de la masa m está situado en una posición inicial {x, y}.Tiene una velocidad inicial de vectores de {vx, vy} (puede ser {0,0}).

El objetivo es un punto en {xo,yo}.El buque tiene que alcanzar el objetivo de tener una velocidad de {vxo, vyo} (o cerca de ella), siguiendo la más corta trayectoria.

Hay una función llamada update(dt) que se llama con frecuencia (es decir,30 veces por segundo).En esta función, el barco puede modificar su posición y trayectoria, mediante la aplicación de "impulsos" a sí mismo.La magnitud de los impulsos es binario:se puede aplicar en una dirección dada, o no se aplican en absoluto).En el código, se parece a esto:

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

La primera ??? hay que indicar que en algunas ocasiones (supongo) que sería mejor no "impulso" y abandonar el barco, "la deriva".El segundo ??? parte consiste en cómo calcular el impulso angular en un determinado dt.

Estamos en el espacio, por lo que podemos ignorar cosas como el rozamiento del aire.

Aunque sería muy bonito, yo no estoy buscando a alguien para que este código para mí;Pongo el código de allí, así que mi problema es claramente entendido.

Lo que necesitas es una estrategia, una forma de atacar este.Sé que algunos de física básica, pero no soy experto.Por ejemplo, este problema tiene un nombre?Ese tipo de cosas.

Muchas gracias.

EDITAR:Beta proporciona una estrategia válida para el este y el Juez amablemente implementado directamente en LÖVE, en los comentarios.

EDIT2:Después de más de googlear encontré también openSteer.Es en C++, pero se hace lo que yo pretendía.Probablemente será útil para cualquier persona llegar a esta cuestión.

¿Fue útil?

Solución

Se llama planificación de movimientos, y no es trivial.

Aquí hay una forma sencilla de obtener una trayectoria no óptimo:

  1. Detener. Aplicar de empuje opuesta a la dirección de la velocidad hasta la velocidad es cero.
  2. Calcular la última etapa, que será el opuesto de la primera, un empuje constante desde un principio que obtiene el barco a x0 y v0. El punto de partida será a una distancia de | v0 | ^ 2 / (2 * empuje) de x0.
  3. llegar a ese punto de partida (y luego hacer la última etapa). Ir de un punto a otro de pie es fácil: empuje hacia ella hasta que esté a mitad de camino, a continuación, empuje hacia atrás hasta que la detenga.

Si desea un enfoque rápido y sucio a una trayectoria óptima, se podría utilizar un enfoque iterativo: Comienzo con el enfoque no óptimo, más arriba; eso es sólo una secuencia temporal de los ángulos de empuje. Ahora trata de hacer pequeñas variaciones de esa secuencia, manteniendo una población de secuencias que se acercan a la meta. rechazar el peor de los casos, experimentar con los mejores - si te sientes audaz que podría hacer de este un algoritmo genético. - y con suerte que comenzará a redondear las esquinas

Si desea que la respuesta exacta, utilice el cálculo de variaciones. Voy a tomar una grieta en eso, y si lo consigo voy a publicar la respuesta aquí.

EDIT:. Aquí está la solución exacta a un problema más sencillo

Supongamos que en lugar de un empuje que podemos señalar en cualquier dirección, tenemos cuatro propulsores fijos que apuntan en la {+ X, + Y, -X, -Y} direcciones. En cualquier momento dado vamos a cocción a más uno de los +/- X y como máximo uno de los +/- Y (no hay punto en cocción + x y -X al mismo tiempo). Así que ahora los problemas de X e Y son independientes (no están en el problema original, ya que el empuje debe ser compartida entre X e Y). Ahora tenemos que resolver el problema 1-D -. y aplicarlo dos veces

Resulta que la mejor trayectoria implica empujando en una dirección, luego el otro, y no vamos a volver a la primera vez. (Inercia es útil sólo si la solución del otro eje tardará más que la tuya para que tenga tiempo de matar.) Resolver el problema de la velocidad en primer lugar: supongamos (WLOG) que su velocidad de destino es mayor que su velocidad inicial. Para llegar a la velocidad de destino se necesita un período de empuje (+) de la duración

T = (Vf - Vi)/a

(estoy usando Vf: velocidad final, Vi: velocidad inicial, a:. Magnitud del empuje)

cuenta de que si eso es todo lo que hacemos, la ubicación no saldrá bien. La ubicación final real será

X = (Vi + Vf)T/2

Así que tenemos que añadir una corrección de

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

Ahora para hacer la ubicación sale bien, añadimos un período de empuje en una dirección antes que, y un período igual en la dirección opuesta después . Esto dejará la velocidad final sin ser molestados, pero darnos un poco de desplazamiento. Si la duración de este primer período (y el tercero) es t, entonces el desplazamiento obtenemos de él es

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

La +/- depende de si empujamos + a continuación - o - a continuación +. Supongo que es +. Se resuelve la ecuación cuadrática:

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

Y ya hemos terminado.

Otros consejos

En ausencia de información adicional, podemos asumir que hay son 3 las fuerzas que actúan sobre la nave espacial y, finalmente, el dictado de su trayectoria:

  • "los impulsos":[usuario/programa de control] de la fuerza.
    El usuario (o el programa) parecen tener un completo control sobre este, es decir,controla la dirección del impulso y su empuje (probablemente dentro de un 0 a máximo rango)
  • alguna fuerza externa:llamamos gravedad, lo que sea...
    Dicha fuerza puede ser motivado por varias fuentes, pero sólo estamos interesados en el resultado combinado de la fuerza:en un determinado momento y espacio de esta fuerza externa actúa sobre la nave con una determinada fuerza y dirección.El usuario/programa no tiene ningún control sobre estos.
  • la inercia:esto está relacionado con el barco de la velocidad de la corriente y la dirección.Esta fuerza hace que el barco siga en su dirección actual en su velocidad actual.Puede haber otros [espacio-edad] los parámetros de control de la inercia, pero en general, es proporcional a la velocidad y a la nave de la masa (Intuitivamente, será más fácil llevar un barco a una parada si su velocidad de la corriente es menor y/o si su masa es menor)

Al parecer, el usuario/programa sólo los controles (dentro de límites) de la primera fuerza.
No está claro, a partir de la pregunta, si el problema en cuestión es:

  • [Problema] para escribir un programa que descubre la dinámica del sistema (y/o se adapta a los cambios de estas dinámicas).
    o..
  • [Problema B] para sugerir un modelo de una fórmula que puede ser usada para calcular la fuerza combinada eventualmente aplicado a la nave:el "pesaba" la suma de la de control de los impulsos y los otros dos del sistema/basada en la física de las fuerzas.

La segunda cuestión, el Problema de B, es más fácil y brevemente explicado, así que vamos a sugerir el siguiente 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])

Tenga en cuenta que el modelo anterior supone una constante fuerza Externa constante (tanto en términos de su intensidad y dirección);que es:similar a la de un campo gravitatorio relativamente distantes de la zona de muestra (como decir que la Tierra la gravedad, considera que en el lapso de un campo de fútbol).Si la escala del área es grande en relación a la fuente(s) de fuerzas externas, el término medio de las fórmulas de arriba, a continuación, debe ser modificado para incluir:un trigonométricas factor basado en el ángulo entre el centro de la fuente y la posición actual y/o un [al revés] factor proporcional en función de la distancia entre el centro de la fuente y la posición actual.
Del mismo modo, la Nave de la misa se supone que permanece constante, bien podría ser una variable, basado decir en la masa de la Nave al vacío, para que el peso del combustible se extrae/añadido como el juego progresa.

Ahora...Todo lo anterior supone que la dinámica del sistema son controlados por el diseñador del juego:esencialmente la elección de un conjunto de valores para el parámetro mencionado y, posiblemente, añadir un poco de complejidad en los cálculos de la fórmula (y también asegurar la escala adecuada, en general, para "mantener" el buque dentro de la zona de la pantalla).

¿Y si en lugar de ello, la dinámica del sistema se programa fácilmente en el juego (y que se supone oculto/aleatorio), y en la tarea es escribir un programa que progresivamente decidir la dirección de empuje y valor de los impulsos para conducir la nave a su destino, de manera que su velocidad en el objetivo de estar lo más cerca posible a getTargetVelocity()?Este es el "Problema".

Este tipo de problema puede ser abordado con un Controlador PID.En un nuthell, un controlador "decide" que cantidad de acción (en este juego el caso de = que impulso el ángulo y la cantidad de empuje para aplicar), basado en tres, de ponderación de factores, vagamente definidas a continuación:

  • en qué medida-nos son los valores actuales de "punto de ajuste":esta es la P=parte Proporcional de PID
  • cómo de rápido se nos aproxima el "punto de ajuste":este es el D=Derivada de la parte de PID
  • cuánto tiempo y cuánto nos han alejado de los "set point":esta es la I=Intergral parte de PID

Menos sofisticado controlador podría, por ejemplo, sólo utilizar el factor proporcional.Esto podría resultar en la oscilante, a veces con mucha amplitud a cada lado del punto de ajuste ("yo soy X unidades de distancia de donde se supone que debo ser:déjame tirar del volante de la dirección y pulse sobre el gas").Tal superación del punto de ajuste son templados por la Derivada del factor ("Sí, yo todavía no estoy donde debo estar, pero el progreso que he hecho desde la última vez que la verificación es muy grande:mejor un poco más lento").Finalmente, la parte Integral toma en cuenta el hecho de que todas las cosas en igualdad de condiciones con respecto al conjunto Proporcional y Derivativo parte, un menor o mayor medida sería apropiado dependiendo de si hemos sido "fuera de pista" por un largo tiempo o no y de mucho fuera de pista que hemos estado todo este tiempo (por ejemplo."Últimamente hemos estado haciendo un seguimiento más cercano a donde se supone que estamos, no hay punto de hacer erupción se mueve")

Podemos discutir los detalles de la implementación de controladores PID para las necesidades específicas de la nave espacial juego, si eso es efectivamente lo que se requiere.La idea era ofrecer un sabor de lo que se puede hacer.

para obtener sólo desde la posición actual hasta el destino con una velocidad inicial, a continuación, aplicar el empuje a lo largo de la diferencia normalizada entre el camino más corto y la velocidad actual. En realidad no necesita el á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)

Tenga en cuenta que esto no tiene la velocidad de destino en cuenta, ya que es muy serio.

I tiene una muy pequeña módulo Lua para la manipulación de vectores 2D en este bin pasta . Usted es bienvenido a utilizarlo. El código anterior se reduciría a:

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

¿Está expulsando de combustible? Su masa va a cambiar con el tiempo si lo son.

El empuje es una fuerza de reacción. Es la razón de cambio de masa, veces la velocidad de los gases de escape con respecto a la nave espacial.

¿Tiene fuerzas externas? Si lo hace, éstos necesidad de entrar en el cálculo de los impulsos.

Vamos a suponer un empuje mágico con ninguna masa de ser expulsado, y no hay fuerzas externas.

Impulse tiene unidades de impulso. Es la integral de una fuerza con el tiempo.

En primer lugar, usted tiene que averiguar exactamente lo que las llamadas a la API "empuje" y el impulso. Si usted está alimentando a un empuje multiplicado por un escalar (número), entonces applyImpulse tiene que hacer algo más para su entrada para poder utilizarlo como un impulso, ya que las unidades no coinciden.

Asumiendo que su "empuje" es una fuerza, entonces se multiplican por el empuje que el intervalo de tiempo (1/30 de segundo) para conseguir el impulso, y romper los componentes.

No sé si estoy respondiendo a su pregunta, pero es de esperar que le ayuda a comprender la física un poco.

Es más fácil pensar en si se separa la velocidad de la nave en componentes, paralelo y perpendiculares para el vector de velocidad de destino.

Teniendo en cuenta a lo largo del eje perpendicular, el barco quiere venir en línea con la posición de destino tan pronto como sea posible, y luego se quedan allí.

A lo largo del eje paralelo, se debe acelerando en la dirección que lo traerá cerca de la velocidad de destino. (Obviamente, si la aceleración que lleva distancia desde el punto de destino, tendrá que decidir qué hacer. Mosca más allá del punto y haga doble vuelta?)

Me gustaría hacer frente a los dos de ellos por separado, y probablemente perpendiculares primero. Una vez que funcione, y si eso no prueba lo suficientemente agradable, se puede empezar a pensar en si hay maneras de conseguir el barco para disparar ángulos inteligentes entre perpendiculares y paralelas.

(EDIT:. También, se me olvidó mencionar, esto llevará algún ajuste para hacer frente a la situación en la que se compensan mucho en la dirección perpendicular pero no mucho en la dirección paralela La lección importante aquí es llevar a los componentes, lo que le da números de interés en los que basar una decisión.)

Su ángulo es la tangente inversa del Frente / Al lado

Así ángulo = InvTan (VY / VX)

Sin seguro de lo que están hablando de su relación con querer deriva ??

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top