math - tutorial - unity 2d colisiones
2D movimiento de movimiento de nave espacial (5)
Necesitas tener tres variables para tu nave, que actualizas en cada paso de tiempo de física en función de las fuerzas que actúan sobre ella. Estos serán masa, posición y velocidad. (tenga en cuenta que la posición y la velocidad son números únicos, pero vectores). En cada paso de tiempo de física, actualiza la posición según la velocidad y la velocidad en función de la aceleración. calcula la aceleración en función de las fuerzas que actúan en el barco (gravedad, fricción, motores)
La ecuación de Newton para la fuerza es F = M*A
Podemos reordenar eso a A = F/M
para obtener la aceleración. Básicamente, necesitas saber cuánto debe acelerar la nave y en qué dirección (vector), luego sumar esa aceleración a la velocidad del barco y añadir la velocidad del barco a su posición.
Aquí está el código que debe ejecutar cada paso del tiempo de física (espero que pueda completar los espacios en blanco) por favor pregunte si esto no es suficiente detalle
gravity = //calculate force of gravity acting on ship from Newton''s law of universal gravitation
friction = //ten percent of the ship''s velocity vector, in the opposite direction
engines = 0
if (engines_are_firing)
engines = 500
forces = gravity + friction + engines
acceleration = forces / ship.mass
ship.velocity += acceleration
ship.position += velocity
redraw()
Intento hacer un juego de nave espacial de arriba hacia abajo y quiero que el movimiento sea algo realista. 360 grados con inercia, gravedad, etc.
Mi problema es que puedo hacer que la nave se mueva 360 ° con inercia sin problema, pero lo que tengo que hacer es imponer un límite para la velocidad de los motores sin limitar otras fuerzas que empujan o tiran de la nave.
Por lo tanto, si la velocidad del motor es un máximo de 500 y el barco va a 1000 desde un pozo de gravedad, el barco no irá a 1500 cuando los motores estén encendidos, pero si se aleja del ángulo, entonces podría ralentizarse abajo.
Por lo que vale, estoy usando Construct , y todo lo que necesito es la matemática de eso.
Gracias por cualquier ayuda, me voy a calvo de tratar de resolver esto.
Bueno, consideremos primero el problema realista y veamos por qué esto no funciona y cómo tenemos que diferir de él. En el espacio, mientras tus motores estén encendidos, acelerarás. Su velocidad solo está limitada por su combustible (y, de hecho, puede acelerar más rápido una vez que haya gastado algo de combustible porque mueve menos masa).
Para darle a este modelo una velocidad máxima efectiva, puedes considerar partículas en el espacio que te ralentizan y provocan fricción. Cuanto más rápido vayas, más partículas estás golpeando y más rápido las estás golpeando, así que eventualmente a una velocidad lo suficientemente rápida, estarás golpeando suficientes partículas, la cantidad de desaceleración que hacen anula exactamente la cantidad de aceleración de tu motor está haciendo.
Este modelo realista NO suena como lo que quieres. La razón es: tienes que introducir la fricción. Esto significa que si cortas los motores, automáticamente comenzarás a disminuir la velocidad. Probablemente pueda contar esto como una de las fuerzas involuntarias que no desea.
Esto nos deja reducir la fuerza efectiva de su motor a 0 al alcanzar cierta velocidad. Ahora ten en cuenta que si vas a la velocidad máxima en la dirección norte, aún quieres que la fuerza te empuje en dirección este, por lo que tus motores no deben cortarse solo por la velocidad bruta, sino que en función de la velocidad tu yendo en la dirección que apuntan sus motores.
Entonces, para las matemáticas:
Desea hacer un producto de puntos cruzados entre su vector de apuntamiento del motor y su vector de velocidad para obtener la velocidad efectiva en la dirección que apuntan sus motores. Una vez que tienes esta velocidad, digamos, 125 mph (con una velocidad máxima de 150), puedes reducir la fuerza de tus motores (150-125) / 150 * (Fuerza de los motores).
Esto cambiará drásticamente el gráfico de velocidad de cuánto tiempo le llevará acelerar hasta la velocidad máxima. A medida que te acercas a toda velocidad, tus motores se vuelven cada vez menos poderosos. Pruébelo y vea si es lo que quiere. Otro enfoque es simplemente decir Fuerza de motores = 0 si el producto escalar es> = 150, de lo contrario, tiene plena fuerza. Esto le permitirá acelerar linealmente a su velocidad máxima, pero no más.
Ahora que lo pienso, este modelo no es perfecto, porque puedes acelerar a 150 mph en la dirección norte, y luego girar hacia el este y acelerar a 150 mph yendo en esa dirección para un total de 212 mph en dirección noreste , entonces no es una solución perfecta.
Tu pregunta es difícil de entender, pero parece que no estás usando la física real para este juego. ¿Has considerado usar ecuaciones físicas reales como velocidad, aceleración, fuerza, etc.?
Editar: Después de sus ediciones, creo que tengo una mejor comprensión. Simplemente está haciendo un seguimiento de la velocidad actual (o algo similar) pero no realiza un seguimiento de la fuerza de donde proviene esa velocidad. El barco no debe almacenar ninguna de esa información (que no sea el empuje del motor); debe provenir del entorno en el que se encuentra el barco.
Por ejemplo, el entorno tiene un vector de gravedad (fuerza direccional), por lo que tendría que tenerlo en cuenta al calcular la fuerza direccional proporcionada por el motor.
Tu nave debería almacenar su propia fuerza, aceleración y velocidad del motor.
Realmente me gusta la respuesta de Wongsungi (con el factor de Lorentz), pero quería señalar que el código se puede simplificar para tener menos operaciones de coma flotante.
En lugar de calcular el factor de Lorentz (que a su vez es recíproco) y luego dividir por él, así:
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
simplemente multiplique por el recíproco del factor de Lorentz, así:
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
Esto elimina una operación de coma flotante del código, y también elimina la necesidad de sujetar b a DBL_MIN (ahora puede ser bloqueado a 0 porque ya no estamos dividiendo). ¿Por qué dividir por el recíproco de x cuando puedes simplemente multiplicar por x ?
Además, si puede garantizar que la magnitud de v nunca superará c , entonces puede eliminar la prueba de que b sea menor que cero.
Finalmente, puede eliminar dos operaciones adicionales sqrt()
utilizando length_squared()
lugar de length()
en la declaración if
externa:
if (new_v.length_squared() > v.length_squared())
{
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b < 0) b = 0;
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
}
Esto solo puede hacer una diferencia de 0.1% en la velocidad, pero creo que el código es más simple de esta manera.
Tome una página de física relativa , donde los objetos no pueden exceder la velocidad de la luz :
(Consulte a continuación el fragmento de código de C ++ en funcionamiento y la demostración en ejecución [solo Windows]).
- Establezca la constante c a la velocidad máxima que un objeto puede alcanzar (la "velocidad de la luz" en su juego).
- Si aplicar una fuerza aumentará la velocidad del objeto, divida la aceleración (cambio en velocidad) por el factor de Lorentz. La condición if no es realista en términos de relatividad especial, pero mantiene la nave más "controlable" a altas velocidades.
- Actualización: Normalmente, la nave será difícil de maniobrar cuando se va a velocidades cercanas a c porque cambiar de dirección requiere una aceleración que empuja la velocidad más allá de c (El factor de Lorentz terminará escalando la aceleración en la nueva dirección a casi nada). Para recuperar la maniobrabilidad, utilice la dirección en que habría estado el vector de velocidad sin la escala de Lorentz con la magnitud del vector de velocidad escalado.
Explicación:
Definición del factor de Lorentz, donde v es la velocidad yc es la velocidad de la luz:
Esto funciona porque el factor de Lorentz se acerca al infinito a medida que aumenta la velocidad. Los objetos necesitarían una cantidad infinita de fuerza aplicada para cruzar la velocidad de la luz. A velocidades más bajas, el factor de Lorentz está muy cerca de 1, aproximándose a la física newtoniana clásica.
Gráfico del factor de Lorentz a medida que aumenta la velocidad:
Nota: anteriormente intenté resolver un problema similar en mi juego de asteroides jugando con ajustes de fricción. Acabo de presentar esta solución mientras leo tu pregunta ^^
Actualización: Intenté implementar esto y encontré un defecto potencial: la aceleración en todas las direcciones es limitada a medida que se aproxima la velocidad de la luz c, ¡incluida la desaceleración! (Contra-intuitivo, ¿pero sucede esto con la relatividad especial en el mundo real?) Supongo que este algoritmo podría modificarse para tener en cuenta las direcciones de los vectores de velocidad y fuerza ... El algoritmo ha sido modificado para tener en cuenta las direcciones de los vectores para que el barco no "pierda controlabilidad" a altas velocidades.
Actualización: Aquí hay un fragmento de código de mi juego de asteroides, que usa el factor de Lorentz para limitar la velocidad de los objetos del juego. ¡Funciona bastante bien!
actualización: * se agregó una demostración descargable (solo Windows) de este algoritmo en acción. No estoy seguro si todas las dependencias fueron incluidas en el zip; por favor, avíseme si falta algo. Y diviértete ^^
void CObject::applyForces()
{
// acceleration: change in velocity due to force f on object with mass m
vector2f dv = f/m;
// new velocity if acceleration dv applied
vector2f new_v = v + dv;
// only apply Lorentz factor if acceleration increases speed
if (new_v.length() > v.length())
{
// maximum speed objects may reach (the "speed of light")
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b <= 0) b = DBL_MIN;
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
}
// apply acceleration to object''s velocity
v += dv;
// Update:
// Allow acceleration in the forward direction to change the direction
// of v by using the direction of new_v (without the Lorentz factor)
// with the magnitude of v (that applies the Lorentz factor).
if (v.length() > 0)
{
v = new_v.normalized() * v.length();
}
}