Creare un movimento della macchina abbastanza buono non è difficile (ma questo post sarà piuttosto lungo). Dovrai "simulare" un paio di forze di base per rendere la macchina in movimento fisicamente plausibile.
(Tutti gli esempi di codice sono pseudocodici.)
Accelerazione
Innanzitutto, avrai ovviamente bisogno di accelerazione. Qualcosa di semplice come farebbe la seguente riga:
acceleration_vector = forward_vector * acceleration_input * acceleration_factor
forward_vector
- Un vettore che punta nella stessa direzione della macchina.
acceleration_input
- L'ingresso dovrebbe essere nell'intervallo [-1, 1].
acceleration_factor
- Il valore dell'accelerazione (pixel / secondo ^ 2 o qualunque sia la tua unità).
Timone
Lo sterzo è anche abbastanza semplice. In linea di principio, ciò che farai è ruotare il vettore anteriore dell'auto in modo che punti in un'altra direzione.
steer_angle = steer_input * steer_factor
new_forward_vector = rotate_around_axis(forward_vector, up_vector, steer_angle)
Tuttavia, potresti riscontrare una complicazione qui. Se il tuo input è tramite una tastiera, il suo valore sarà -1 o 1, il che significa che la tua auto girerebbe istantaneamente. Puoi risolvere questo problema usando un'interpolazione lineare molto semplice (lerping):
amount = time_since_last_frame * steer_lerp_factor
forward_vector = lerp(forward_vector, new_forward_vector, amount)
L'importo dovrebbe dipendere dal tempo in modo tale che il movimento non dipenda dalla frequenza dei fotogrammi. L'importo dovrebbe essere tra [0, 1] e più piccolo è, più agevole sarà la transizione tra il vecchio e il nuovo vettore.
(A questo punto scoprirai che la macchina sterzerà anche se è ferma. Per evitare ciò, moltiplica steer_angle
per current_speed / max_speed
dove max_speed
è definita una costante da te.)
In movimento
Ora applicheremo l'accelerazione e sposteremo la macchina di un certo numero di pixel in base alla sua velocità, accelerazione e sterzo. Vorremmo anche limitare la velocità dell'auto in modo che non finisca per muoversi all'infinito.
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
La tua auto ora sta scivolando
Se ho ragione, ora la tua auto dovrebbe sembrare scivolare ogni volta che giri come se fosse sul ghiaccio. Questo perché non c'è attrito. Su un'auto reale c'è un alto attrito laterale (a causa delle ruote che non sono in grado di ruotare lateralmente: P).
Dovrai ridurre la velocità laterale. Non riducendolo completamente, puoi anche far sembrare la macchina alla deriva.
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
Dato che stiamo parlando di attrito, potresti anche voler avere una forza (di attrito) che riduca la tua velocità in modo tale che quando smetti di accelerare, la tua auto alla fine si fermerà.
backwards_friction = -velocity_vector * backwards_friction_factor
Il tuo codice per spostare la macchina ora dovrebbe apparire così:
// 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
Note di chiusura
Ho menzionato come applicare lerping allo sterzo; Penso che potresti dover fare la stessa cosa per l'accelerazione e forse anche per l'angolo di sterzata (dovrai memorizzare i loro valori dal fotogramma precedente e derivarne da quello). Anche tutti i vettori relativi all'auto (avanti, destra, su) devono essere di lunghezza 1.
Inoltre, l'attrito è un po 'più complicato di quello che ho mostrato qui. Dovresti sempre assicurarti che la sua lunghezza non sia mai maggiore di quella dell'accelerazione necessaria per fermare la macchina (altrimenti l'attrito farebbe muovere la macchina nella direzione opposta). Quindi dovresti avere qualcosa del tipo:
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))