Frame Independent Movement


11

Ho letto altri due thread qui sul movimento: movimento basato sul tempo Vs movimento basato sulla frequenza dei fotogrammi? e quando devo utilizzare un passaggio temporale fisso o variabile?

ma penso che mi manchi una conoscenza di base del movimento indipendente dal frame perché non capisco di cosa stia parlando nessuno di questi thread.

Sto seguendo i tutorial SDL di lazyfoo e ho seguito la lezione indipendente dal frame. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

Non sono sicuro di ciò che la parte di movimento del codice sta cercando di dire, ma penso che sia questo (per favore correggimi se sbaglio): per avere un movimento indipendente dal frame, dobbiamo scoprire fino a che punto un oggetto ( es. sprite) si sposta in un determinato intervallo di tempo, ad esempio 1 secondo. Se il punto si sposta a 200 pixel al secondo, allora devo calcolare di quanto si sposta all'interno di quel secondo moltiplicando 200 pps per 1/1000 di secondo.

È giusto? La lezione dice:

"velocità in pixel al secondo * tempo dall'ultimo fotogramma in secondi. Quindi se il programma funziona a 200 fotogrammi al secondo: 200 pps * 1/200 secondi = 1 pixel"

Ma ... pensavo che stessimo moltiplicando 200 pps per 1/1000 di secondo. Cos'è questa attività con i frame al secondo?

Gradirei se qualcuno potesse darmi una spiegazione un po 'più dettagliata su come funziona il movimento indipendente dal frame.

Grazie.

INOLTRE:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

Questo è il codice che sposta un punto sullo schermo. Penso di avere tutto corretto finora. Si sposta sullo schermo ma succede qualcosa di strano che non riesco a spiegare. Si suppone che il punto rimanga su y = 580 quando arriva a un valore maggiore di quel valore y. Tuttavia, ogni volta che eseguo il programma, il punto finirà in una posizione diversa, il che significa da un po 'a molto più di 580, quindi il punto è a metà o più della metà dello schermo (il punto è 20 pixel, schermo dimensioni 800x600). Se faccio qualcosa come fare clic e tenere premuta la barra del titolo del programma, quindi rilasciare, il punto scompare dallo schermo. Come mai è variabile ogni volta? Per quanto riguarda il problema della barra del titolo, penso che sia perché quando mi aggrappo alla barra del titolo, il timer è ancora in esecuzione e il tempo trascorso aumenta, con conseguente distanza maggiore il punto si sposta nel fotogramma successivo. È giusto?


La tua aggiunta è in realtà un'altra domanda. Dovresti farne una seconda domanda invece di aggiungerla a quella esistente. Si può rispondere facilmente anche se: basta calcolare il movimento y, ad es. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);quindi fai:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack

Risposte:


10

NOTA: tutte le frazioni devono essere galleggianti.

Il movimento indipendente dalla cornice funziona basando il movimento fuori dal tempo. Ottieni la quantità di tempo trascorso dall'ultimo fotogramma (quindi se ci sono 60 fotogrammi in un secondo, ogni fotogramma impiega 1,0 / 60,0 secondi, se tutti i fotogrammi impiegano lo stesso tempo) e scopri quanto movimento si traduce in.

Se vuoi che la tua entità si sposti di una determinata quantità di spazio per una determinata unità di tempo (diremo 100 pixel per ogni secondo di tempo), puoi scoprire quanti pixel dovresti spostare per fotogramma moltiplicando la quantità di movimento per secondo (100 pixel) per il tempo trascorso in secondi (1.0 / 60.0) al fine di capire quanto movimento dovrebbe avvenire nel fotogramma corrente.

Funziona determinando la quantità di movimento che dovresti eseguire per fotogramma usando la quantità di tempo trascorso e una velocità definita con una certa unità di tempo (sono preferibili secondi o millisecondi). Quindi il tuo calcolo potrebbe apparire come:movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

Spero che abbia avuto un certo senso per te.

Voglio spostare il mio ragazzo di 200 pixel a destra ogni secondo. Se il fotogramma corrente viene eseguito 50 millisecondi dopo il fotogramma precedente, allora dovrei spostare il mio ragazzo di una frazione della velocità precedentemente specificata (che era di 200 pixel). Dovrei spostarlo di 50/1000 di distanza perché è passato solo un 1/20 (50/1000 = 1/20) di tempo. Pertanto avrebbe senso spostarlo solo di 10 pixel (se si verificassero altri 19 fotogrammi, a 50 millisecondi l'uno dall'altro, la quantità totale di movimento in quel secondo sarebbe di 200 pixel, la quantità che volevamo).

Il modo in cui funziona il movimento indipendente dai frame è che i frame di solito si verificano a intervalli di tempo variabili (c'è un tempo diverso tra i frame successivi). Se spostiamo costantemente un'entità a una distanza costante ogni fotogramma, il movimento si basa sulla frequenza dei fotogrammi. Se c'è molto tempo tra i frame, il gioco sembrerà muoversi troppo lentamente e se non c'è molto tempo tra i frame, il gioco sembrerà accelerare. (troppo poco tempo tra i frame = molti frame = più movimento) Per ovviare a questo, usiamo una velocità in termini di tempo e teniamo traccia del tempo tra i frame. In questo modo sappiamo quanto tempo è trascorso dall'ultimo aggiornamento della posizione e quanto oltre dovremmo spostare l'entità.

Frame al secondo: questa è la quantità di frame che si verificano al secondo. Di solito un frame rate è quante volte il gioco viene disegnato / reso al secondo o quante volte il ciclo di gioco viene completato al secondo.

Passo temporale variabile verso il verso fisso: si riferisce alla quantità di tempo tra i frame. Di solito, il tempo tra i frame non sarà costante. Alcuni sistemi / core come la fisica avranno bisogno di alcune unità di tempo per simulare / eseguire qualcosa. Di solito, i sistemi fisici sono più stabili / scalabili se la fase temporale è fissa. La differenza tra i passi temporali fissi / variabili è nei nomi. I passi temporali fissi sono come sembrano: i passi temporali che si verificano ad un ritmo fisso. Gli intervalli di tempo variabili sono intervalli di tempo che si verificano a velocità di tempo variabili / diverse.


Nell'esempio che dai, 50 millisecondi è il tempo per ogni fotogramma, giusto? E quello è stato calcolato da 1000 / FPS? E quindi il movimento necessario per rendere ogni fotogramma è pixel al secondo * 50/1000?
ShrimpCrackers

hm, mi sono reso conto che i millisecondi per ogni periodo di tempo sarebbero probabilmente variabili, no? Qualcosa come getTicks () - startTicks sarebbe sempre diverso e non costante.
ShrimpCrackers

@Omnion: se si specifica la distanza in "pixel al secondo" non è possibile utilizzare i millisecondi ... dovrebbe essere 1.0 / 60.0 e non 1000/60, il che comporterebbe qualcosa di completamente diverso.
Bummzack,

@ShrimpCrackers sì, il tempo trascorso cambia. Immagina un PC più vecchio che non è in grado di eseguire il rendering di 60 fps. Volete comunque che il gioco funzioni alla stessa velocità (ma non agli stessi fps) su una macchina del genere.
Bummzack,

quindi, nel tutorial di lazyfoo, cosa significa 1000 in deltaticks / 1000.f? FPS? 1000 millisecondi? Sono un po 'confuso in questo momento. Sembra che l'FPS sia necessario per determinare il tempo richiesto per ogni frame, ma che in realtà non si calcoli nel movimento.
Gamberetti Cracker

7

Nella dinamica dei frame il tuo codice per (ad esempio) lo spostamento di un'entità sarebbe simile al seguente:

x = x + speedPerFrame

Se vuoi essere indipendente dal frame, potrebbe apparire così:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

grazie, ha senso. Ho un'altra domanda sopra.
ShrimpCrackers

1

Per quanto riguarda la domanda aggiuntiva.

Il tuo punto si ferma in posizioni diverse ogni volta perché non controlli il limite (y> 580) quando lo sposti. Smetti di aggiornarlo ulteriormente una volta superato il 580.

Nell'ultimo fotogramma prima di incrociare 580 potresti iniziare da 579 o potresti essere a 570 o potresti essere a 100. Potresti anche fare un passo avanti di 1 pixel o 1000, a seconda del tempo impiegato dall'ultimo fotogramma per essere eseguito.

Cambia la tua condizione IF in qualcosa del genere e dovresti andare bene.

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.