Parlare di tempo significa considerare l'intervallo in secondi (o piuttosto in millisecondi) che separa le diverse chiamate al metodo Update
. Essa influenza pesantemente il modo in cui viene gestita la logica di gioco. Con XNA possiamo scegliere tra due modalità:
- fixed time step (a passo fisso)
- variable time step (a passo variabile)
Possiamo attivare la modalità a passo fisso in qualunque punto della classe Game
, assegnando la proprietà IsFixedTimeStep:
IsFixedTimeStep = true; // per attivare
IsFixedTimeStep = false; // per disattivare
In modalità fixed time step il metodo Update
viene invocato ad intervalli fissi, la cui durata è specificata dall'utente assegnando la proprietà TargetElapsedTime:
TargetElapsedTime = TimeSpan.FromSeconds(1.0 / FPS_VALUE);
dove FPS_VALUE
è il numero di fotogrammi al secondo desiderato. Nel caso di passo fisso, XNA gestirà specialmente quei casi in cui il metodo Update
risultasse troppo lento.
Ad esempio, se il sistema fisico risultasse in difficoltà perché ci sono molte entità in collisione tra loro, rendendo i calcoli eccessivamente pesanti e il metodo Update dura più del TargetElapsedTime
, allora XNA imposterà la proprietà gameTime.IsRunningSlowly a true
e lascerà perdere alcune chiamate al metodo Draw
, in modo da ridurre il framerate percepito dall'utente ma concentrando la potenza di calcolo residua sul metodo Update
in modo che i calcoli della logica vengano prioritizzati e restino il più coerenti possibile con il tempo reale.
Passo fisso
In modalità a passo fisso, siccome sappiamo che il metodo Update viene chiamato ad intervalli fissi, possiamo aggiornare le nostre entità con velocità espresse in
v = unità di movimento/fotogramma
Ad esempio 10 px/fotogramma, significa che ad ogni fotogramma un oggetto si sposta di 10px. Pertanto in cui in ogni fotogramma aggiorniamo le posizioni secondo lo schema:
pt+1 = pt+v
Questo sistema è alternativo a quello più tradizionale in cui (nell'esempio vediamo una integrazione di Eulero in avanti) la velocità è espressa in:
v = unità di movimento/secondi
e gli aggiornamenti si calcolano come:
pt+1 = pt+Δt×v
dove Δt è il numero (floating point, non intero che sarebbe sempre a 0) di secondi passati tra la chiamata t-esima
e la chiamata t+1-esima
al metodo Update.
Δt proviene dalla proprietà gameTime.ElapsedGameTime.TotalSeconds
, che viene calcolata da XNA e passata al metodo Update
ad ogni invocazione. Il GameTime contiene anche altre informazioni utili, come il TotalGameTime
che indica da quanto tempo l'applicazione è in esecuzione.
Passo variabile
Il passo variabile di default non permetterà di realizzare più di 60 fotogrammi al secondo (30 nel caso di Windows Phone 7), anche quando l'hardware fosse ampiamente in grado di farcela. Questo puó non essere il comportamento desiderato e per evitarlo e aggiornare e disegnare tutti i fotogrammi possibili, dovremo disattivare la sincronizzazione con il vertical retrace dello schermo, impostando:
graphics.SynchronizeWithVerticalRetrace = false;
se modifichiamo questa proprietà al di fuori del costruttore del Game
, allora (come per tutte le proprietà del GraphicsDevice
e del GraphicsDeviceManager
) dovremo invocare il metodo:
graphics.ApplyChanges();
che applicherà le modifiche alle opzioni grafiche. Potrebbe persino ricreare il GraphicsDevice
e invocare nuovamente il metodo LoadContent
del gioco per ricreare i contenuti che sono stati invalidati in quanto appartenevano all'istanza precedente del GraphicsDevice
.