Domanda

Sto lavorando a un gioco 2D in cui provo ad accelerare un oggetto fino alla massima velocità utilizzando un codice fisico di base.

Ecco lo pseudocodice per questo:


const float acceleration = 0.02f;
const float friction     = 0.8f;  // value is always 0.0..1.0
      float velocity     = 0;
      float position     = 0;

move()
{
   velocity += acceleration;
   velocity *= friction;
   position += velocity;
}

Si tratta di un approccio molto semplificato che non si basa sulla massa o sull'attrito effettivo (l'attrito nel codice è solo una forza generica che agisce contro il movimento).Funziona bene come "Velocità *= attrito;" La parte impedisce alla velocità di superare un certo punto.Tuttavia, è questa velocità massima e il suo rapporto con l'accelerazione e l'attrito che mi ha un po' perso.

Quello che mi piacerebbe fare è impostare una velocità massima e il tempo necessario per raggiungerla, quindi usarli per ricavare i valori di accelerazione e attrito.

cioè.,


const float max_velocity = 2.0; 
const int   ticks;       = 120; // If my game runs at 60 FPS, I'd like a 
                                // moving object to reach max_velocity in 
                                // exactly 2 seconds.
const float acceleration = ?
const float friction     = ?
È stato utile?

Soluzione

Ho trovato questa domanda molto interessante poiché di recente avevo svolto un lavoro sulla modellazione del movimento del proiettile con resistenza.

Punto 1: Stai essenzialmente aggiornando la posizione e la velocità usando un iterazione di Eulero esplicita/inoltrata dove ogni nuovo valore per gli stati dovrebbe essere una funzione dei vecchi valori.In tal caso, dovresti aggiornare la posizione Primo, quindi aggiornando la velocità.

Punto 2: Esistono modelli fisici più realistici per l'effetto dell'attrito di trascinamento.Un modello (suggerito da Adam Liss) comporta una forza di resistenza proporzionale alla velocità (nota come resistenza di Stokes, che generalmente si applica a situazioni a bassa velocità).Quello che ho suggerito in precedenza prevede una forza di trascinamento proporzionale a piazza della velocità (noto come resistenza quadratica, che generalmente si applica a situazioni ad alta velocità).Affronterò ciascuno di essi in base a come dedurresti le formule per la velocità massima e il tempo necessario per raggiungere effettivamente la velocità massima.Tralascerò le derivazioni complete poiché sono piuttosto coinvolte.


La resistenza di Stokes:

L'equazione per aggiornare la velocità sarebbe:

velocity += acceleration - friction*velocity

che rappresenta la seguente equazione differenziale:

dv/dt = a - f*v

Utilizzando la prima voce in questa tabella integrale, possiamo trovare la soluzione (assumendo v = 0 at = 0):

v = (a/f) - (a/f)*exp(-f*t)

Il massimo (es.terminale) la velocità si verifica quando t >> 0, per cui il secondo termine dell'equazione è molto vicino a zero e:

v_max = a/f

Per quanto riguarda il tempo necessario per raggiungere la velocità massima, si noti che l'equazione non la raggiunge mai veramente, ma tende invece ad essa asintoticamente.Tuttavia, quando l'argomento dell'esponenziale è uguale a -5, la velocità è circa il 98% della velocità massima, probabilmente abbastanza vicina da poterla considerare uguale.È quindi possibile approssimare il tempo alla velocità massima come:

t_max = 5/f

È quindi possibile utilizzare queste due equazioni per risolvere F E UN dato un desiderato vmax E tmax.


Trascinamento quadratico:

L'equazione per aggiornare la velocità sarebbe:

velocity += acceleration - friction*velocity*velocity

che rappresenta la seguente equazione differenziale:

dv/dt = a - f*v^2

Utilizzando la prima voce in questa tabella integrale, possiamo trovare la soluzione (assumendo v = 0 at = 0):

v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)

Il massimo (es.terminale) si verifica quando t >> 0, quindi i termini esponenziali sono molto maggiori di 1 e l'equazione si avvicina:

v_max = sqrt(a/f)

Per quanto riguarda il tempo necessario per raggiungere la velocità massima, si noti che l'equazione non la raggiunge mai veramente, ma tende invece ad essa asintoticamente.Tuttavia, quando l'argomento dell'esponenziale è uguale a 5, la velocità è circa il 99% della velocità massima, probabilmente abbastanza vicina da considerarla uguale.È quindi possibile approssimare il tempo alla velocità massima come:

t_max = 2.5/sqrt(a*f)

che equivale anche a:

t_max = 2.5/(f*v_max)

Per un desiderato vmax E tmax, la seconda equazione per tmax ti dirò cosa F dovrebbe essere, e poi puoi collegarlo all'equazione per vmax per ottenere il valore UN.


Sembra un po' eccessivo, ma in realtà questi sono alcuni dei modi più semplici per modellare il trascinamento!Chiunque Veramente vuole vedere i passaggi dell'integrazione può mandarmi un'e-mail e te li invierò.Sono un po' troppo coinvolti per scrivere qui.

Un altro punto: Non me ne sono accorto subito, ma l'aggiornamento della velocità non è più necessario se si utilizzano invece le formule che ho derivato per v(t).Se stai semplicemente modellando l'accelerazione da fermo e tieni traccia del tempo trascorso dall'inizio dell'accelerazione, il codice sarebbe simile a:

position += velocity_function(timeSinceStart)

dove "velocity_function" è una delle due formule per v(t) e non avresti più bisogno di una variabile di velocità.In generale, qui c'è un compromesso:calcolo v(t) può essere più costoso dal punto di vista computazionale rispetto al semplice aggiornamento della velocità con uno schema iterativo (a causa dei termini esponenziali), ma è garantito che rimanga stabile e limitato.In determinate condizioni (come cercare di ottenere un file molto breve tmax), l'iterazione può diventare instabile ed esplodere, un problema comune con il metodo di Eulero diretto.Tuttavia, mantenendo i limiti sulle variabili (come 0 < F < 1), dovrebbe prevenire queste instabilità.

Inoltre, se ti senti un po' masochista, potresti riuscire a integrare la formula per v(t) per ottenere una soluzione in formato chiuso per p(t), rinunciando così del tutto alla necessità di un'iterazione di Newton.Lascerò questo tentativo ad altri.=)

Altri suggerimenti

Attenzione: soluzione parziale

Se seguiamo la fisica come detto, non v'è massima velocità. Da un punto di vista puramente fisico, aver risolto l'accelerazione ad un valore costante, il che significa che la velocità è sempre crescente.

In alternativa, prendere in considerazione le due forze che agiscono sul vostro oggetto:

  • La forza esterna costante, F , che tende ad accelerare, e
  • La forza di trascinamento, d , che è proporzionale alla velocità e tende a rallentare.

Quindi, la velocità al di iterazione n diventa: v n = v 0 + n F - d v n-1

Hai chiesto di scegliere la velocità massima, v nmax , che si verifica in iterazione nmax.

Si noti che il problema è sotto-vincolato ; vale a dire, F e D sono legati, in modo da poter scegliere arbitrariamente un valore per uno di loro, quindi calcolare l'altro.

Ora che rotolamento della palla, è qualcuno disposto a prendere la matematica?

Attenzione: è brutto e coinvolge potere serie !


Modifica: Perché doe la sequenza n**F** nella prima equazione appare letteralmente a meno che non ci sia uno spazio dopo il <=>

?
velocity *= friction;

Ciò non toglie che la velocità di andare su un certo punto ...

aumenta l'attrito in modo esponenziale (non mi citare su questo) con l'aumentare della velocità, e saranno 0 a riposo. Alla fine, si arriva ad un punto in cui l'attrito = accelerazione.

Così si desidera qualcosa di simile:

velocity += (acceleration - friction);
position += velocity;
friction = a*exp(b*velocity);

Dove si sceglie i valori di A e B. b controllerà il tempo necessario per raggiungere la velocità massima, e un controllerà come bruscamente l'attrito aumenta. (Anche in questo caso, non fare la propria ricerca su questo- sto andando da quello che mi ricordo dal grado 12 della fisica.)

Questo non risponde alla tua domanda, ma una cosa non si deve fare nelle simulazioni di questo tipo è dipendono da un frame rate fisso. Calcolare il tempo dall'ultimo aggiornamento, e utilizzare il delta-T le equazioni. Qualcosa di simile:

static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();

E 'anche un bene per verificare se si perde messa a fuoco e interrompere l'aggiornamento, e quando si guadagna messa a fuoco impostata lastUpdate a 0. In questo modo non si ottiene un enorme deltaT per elaborare quando torni.

Se volete vedere cosa si può fare con molto modelli semplice fisica utilizzando molto semplici di matematica, uno sguardo ad alcuni dei progetti Scratch a http://scratch.mit.edu/ -. è possibile ottenere alcune idee utili e vi sarà certamente divertirsi

Probabilmente non è quello che stai cercando, ma a seconda del motore su cui stai lavorando, potrebbe essere meglio utilizzare un motore costruito da qualcun altro, come lungimirante(per C#).Nota Codeplex è in manutenzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top