Un fattore molto importante nei giochi fullscreen è la stabilità. Situazioni come la pressione del tasto windows, la riduzione ad icona della finestra o la presa di possesso dello schermo da parte di un'altra applicazione possono interrompere la modalità fullscreen e generare errori. Questo non è il comportamento di un programma serio. Non potete costringere il giocatore a dover ricominciare per un banale errore e tanto meno non potete obbligare il giocatore ad uscire dal gioco perchè deve scaricare un'istante la posta. In definitiva dovete permettere al giocatore di ridurre ad icona il gioco fullscreen senza che questi generi errori. Questa situazione è chiamata Lost Device.
un programma directX in finestra subisce un cambio impostazioni dello schermo La situazione di lostdevice è un errore che genera il device durante l'esecuzione dell'istruzione present
Try
device.Present()
Catch e As DeviceLostException
'qui il device è perso
End Try
Quando l'istruzione solleva l'eccezione di tipo DeviceLostException significa che è avvenuta una delle situazioni descritte. Grazie alla gestione degli errori il nostro programma continuerà a girare tranquillamente e ogni volta salterà la presentazione della scena. Questo non risolve però tutti i problemi perchè nel momento in cui riaprirete la finestra si genererà un altro errore di tipo differente che bloccherà il programma. Il motivo di questo è che con la perdita del device abbiamo perso tutti i settaggi inseriti rendendo inutilizzabile ogni istruzione di rendering. Occorrerà quindi eseguire un'istruzione chiamata reset che distruggerà tutte le impostazioni e le reinizializzerà.
Reset device
Innanzitutto una bella critica a chi ha progettato le DirectX9:
1. poteva prevedere una gestione più semplice del problema
2. poteva spiegare per bene come risolvere il problema in managed DirectX
Infatti per la particolare struttura date alle classi occorre ridefinire gli eventi generati dal device dichiarandoli nel codice. Aggiungete alla creazione del device questi handler. Questi servono per dichiarare gli eventi in una classe. In questo caso il Me significa che l'evento verrà scritta nel form (perchè dichiarato lì) ma potrete definire il codice dove volete.
AddHandler device.DeviceLost, AddressOf
Me.InvalidateDeviceObjects
AddHandler device.DeviceReset, AddressOf Me.RestoreDeviceObjects
AddHandler device.Disposing, AddressOf Me.DeleteDeviceObjects
AddHandler device.DeviceResizing, AddressOf Me.EnvironmentResized
e nel form dichiarate questi eventi
Public Sub EnvironmentResized(ByVal sender As Object, ByVal e As_
System.ComponentModel.CancelEventArgs)
'ridimensionamento device
'annullare l'evento per evitare tentativi da parte di DirectX di reinizializzare
e.Cancel = True
End Sub 'EnvironmentResized
Sub deleteDeviceObjects(ByVal sender As Object, ByVal e As EventArgs)
'qui va inserito il codice per cancellare tutto
End Sub
Sub restoreDeviceObjects(ByVal sender As Object, ByVal e As EventArgs)
'qui quello per reinizializzare
End Sub
Sub invalidateDeviceObjects(ByVal sender As Object, ByVal e As EventArgs)
'
End Sub
Questi eventi vengono chiamati da directX quando crea o distrugge uno stato (quindi anche in inizializzazione). Nell'evento delete dovrete mettere il codice per distruggere il materiale non gestito (dopo ci arrivo), in restore il codice per ricaricare i settaggi e invalidate quello che deve verificarsi quando il device non è valido. La prima è quella più importante: l'environmentResize si verifica quando il device viene questo viene ridimensionato in seguito ad un reset. Se si è generata l'eccezione device lost allora occorre verificare se il device è pronto per tornare operativo tramite un'istruzione di reset.
Try
device.TestCooperativeLevel()
Catch e As DeviceLostException
'nulla
Catch e As DeviceNotResetException
'resettiamo
device.Reset(settaggio)
End Try
L'operazione TestCooperativeLevel fa un test del device e genera due tipi di eccezione:
DeviceLostException che indica la permanenza dello stato di DeviceLost
DeviceNotResetException che indica che il device è pronto per un reset.
In questo caso eseguiamo l'istruzione Reset del device
device.Reset(settaggio)
Il parametro settaggio è un PresentParameters, lo stesso che abbiamo usato per creare il device. Da questo momento il device ritorna operativo e funzionale ma ha perso molti dati che dobbiamo ripristinare.
3. Matrici world, view e projection
4. Settaggi per texture e renderState
5. Stato degli shader
6. Luci
7. Oggetti non gestiti
L'ultimo è il problema principale. Quando creiamo texture, mesh e superfici settiamo sempre il parametro POOL. Questo indica la posizione in memoria (se della scheda video o della RAM) in cui verranno depositati i dati. Tutto quello inserito in memoria video è persa e nell'evento delete dovrà essere distrutto e ricaricato nell'evento restore. Per questo il settaggio migliore è Managed che terrà una copia di sicurezza in RAM e non dovrà quindi essere distrutta e ricreata. Testo, shader e tutto ciò che non ha settaggi di gestione POOL non devono essere ricreati. Tenete quindi in memoria i settaggi in modo da recuperarli velocemente.
Il device è ora di nuovo pronto a tutto.
Cambi di risoluzione
L'istruzione reset può essere usata non solo per reimpostare il device ma anche per cambiare risoluzione dello schermo. Se la usate inserendo un settaggio differente (purchè valido ovviamente) potrete cambiare al volo la risoluzione del gioco (cosa che molti giochi famosi neanche fanno). Questo è molto utile quando nello schermo dello opzioni volete impostare le opzioni come ad esempio alcune opzioni di risoluzione o la possibilità di scegliere o meno l'antialiasing.
In finestra
Il reset deve essere chiamato anche quando la finestra viene ridimensionata. In questo modo l'immagine non scomparirà o non perderà definizione (a secondo del modello di scheda video) quando allargherete la finestra. Non vi rimane che fare pratica.
Ecco l'esempio.
Esempio - VB.Net
Esempio 1 - C#
Esempio 2 - C#