No es tan difícil crear un movimiento de automóvil bastante bueno (pero esta publicación será bastante larga). Tendrá que "simular" un par de fuerzas básicas para que el automóvil se mueva físicamente.
(Todos los ejemplos de código son pseudocódigo).
Aceleración
Primero, obviamente necesitarás aceleración. Algo tan simple como lo haría la siguiente línea:
acceleration_vector = forward_vector * acceleration_input * acceleration_factor
forward_vector
- Un vector que apunta en la misma dirección que el automóvil.
acceleration_input
- La entrada debe estar en el intervalo [-1, 1].
acceleration_factor
- El valor de la aceleración (píxeles / segundo ^ 2, o cualesquiera que sean sus unidades).
Direccion
La dirección también es bastante simple. En principio, lo que hará es rotar el vector delantero del automóvil para que apunte en otra dirección.
steer_angle = steer_input * steer_factor
new_forward_vector = rotate_around_axis(forward_vector, up_vector, steer_angle)
Sin embargo, puede encontrar una complicación aquí. Si su entrada es a través de un teclado, su valor será -1 o 1, lo que significa que su automóvil giraría instantáneamente. Puede solucionar esto usando una interpolación lineal muy simple (lerping):
amount = time_since_last_frame * steer_lerp_factor
forward_vector = lerp(forward_vector, new_forward_vector, amount)
La cantidad debe depender del tiempo, de modo que su movimiento no dependa de su velocidad de fotogramas. La cantidad debe estar entre [0, 1] y cuanto menor sea, más suave será la transición entre los vectores antiguos y nuevos.
(En este punto, encontrará que el automóvil girará incluso si está parado. Para evitarlo, multiplique steer_angle
por current_speed / max_speed
, donde max_speed
es una constante definida por usted).
Moviente
Ahora aplicaremos la aceleración y moveremos el automóvil un cierto número de píxeles en función de su velocidad, aceleración y dirección. También queremos limitar la velocidad del automóvil para que no termine moviéndose infinitamente rápido.
current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{
velocity_vector += acceleration_vector * time_since_last_frame
}
position_vector += velocity_vector * time_since_last_frame
Tu auto ahora se está deslizando
Si estoy en lo cierto, su auto ahora debería parecer estar deslizándose cada vez que gira como si estuviera en hielo. Esto se debe a que no hay fricción. En un automóvil real hay una alta fricción lateral (debido a que las ruedas no pueden girar hacia los lados: P).
Necesitará reducir la velocidad lateral. Al no reducirlo por completo, también puede hacer que el automóvil parezca estar a la deriva.
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
Como estamos hablando de fricción, es posible que también desee tener una fuerza (de fricción) que reduzca su velocidad de manera que cuando pare de acelerar, su automóvil finalmente se detenga.
backwards_friction = -velocity_vector * backwards_friction_factor
Su código para mover el automóvil ahora debería verse así:
// Friction should be calculated before you apply the acceleration
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
backwards_friction = -velocity_vector * backwards_friction_factor
velocity_vector += (backwards_friction + lateral_friction) * time_since_last_frame
current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{
velocity_vector += acceleration_vector * time_since_last_frame
}
position_vector += velocity_vector * time_since_last_frame
Notas de cierre
Mencioné cómo debe aplicar lerping a la dirección; Creo que es posible que tenga que hacer lo mismo para la aceleración y posiblemente también para el ángulo de dirección (tendrá que almacenar sus valores del cuadro anterior y aprender de eso). Además, todos los vectores relativos al automóvil (adelante, derecha, arriba) deben ser de longitud 1.
Además, la fricción es un poco más complicada de lo que mostré aquí. Siempre debe asegurarse de que su longitud nunca sea mayor que la de la aceleración necesaria para que el automóvil se detenga (de lo contrario, la fricción haría que el automóvil se mueva en la dirección opuesta). Entonces deberías tener algo como:
dt = time_since_last_frame
backwards_friction.resize(min(backwards_friction.norm(), velocity_vector.norm() / dt))
lateral_friction.resize(min(lateral_friction.norm(), lateral_velocity.norm() / dt))