Il punto di partenza per una applicazione XNA è la classe Game (Microsoft.XNA.Framework.Game
. D'ora in poi la chiameremo, più semplicemente, Game
). Tale classe si occupa di tutte le operazioni descritte finora, ed è persino in grado di fare qualcosa in più.
Durante il resto della lezione esploreremo la classe Game
e le sue "sorelle" Microsoft.XNA.Framework.GameComponent
e Microsoft.XNA.Framework.DrawableGameComponent
. Tutte queste classi sono virtuali, e possiamo ereditarle ed effettuare l'override dei loro metodi per inserire il nostro codice da far eseguire in relazione a certi eventi.
Possiamo lanciare il main loop di una classe che eredita Game
, invocando il metodo:
public void Run();
Eventi
Gli eventi principali del main loop a cui la classe Game
ci permette di reagire sono rappresentati dai suoi metodi:
protected virtual void Initialize();
protected virtual void LoadContent();
protected virtual void Update(GameTime gameTime);
protected virtual void Draw(GameTime gameTime);
L'evento Initialize viene invocato quando l'applicazione deve inizializzare la logica di gioco, ad esempio posizionando l'avatar del giocatore nella sua posizione iniziale, avviando il menu, etc.
L'evento Load viene invocato quando la GPU è pronta e l'applicazione deve caricare risorse (tramite la content pipeline o in modo procedurale) nella memoria della GPU. Parliamo di vertex buffers, index buffers, shaders, textures etc.
Dopo aver invocato Initialize
e Load
allora il main loop vero e proprio viene avviato. All'interno del main loop vengono invocati, a stretta distanza l'uno dall‘altro e in sequenza tra loro i metodo Update e Draw.
Il parametro GameTime che viene loro passato serve per conoscere informazioni sulle tempistiche del main loop, in particolare per sapere a che distanza due iterazioni del main loop avvengono per poter sincronizzare il movimento delle entità e l'aggiornamento della logica con il tempo reale dell'utente. Senza le informazioni del GameTime sapremmo solo "che è passato un fotogramma", senza indicazioni su quanto il fotogramma sia effettivamente durato. Ovviamente un fotogramma a 100fps dura decisamente meno di uno a 25fps, e gli aggiornamenti delle entità ne devono assolutamente tenere conto.
Gli eventi Initialize
, LoadContent
, Update
e Draw
non sono gli unici che la classe Game
mette a disposizione. Abbiamo anche:
protected virtual bool BeginDraw();
protected virtual void BeginRun();
protected virtual void EndDraw();
protected virtual void EndRun();
protected virtual void OnActivated(object sender, EventArgs args);
protected virtual void OnDeactivated(object sender, EventArgs args);
protected virtual void OnExiting(object sender, EventArgs args);
protected virtual bool ShowMissingRequirementMessage(Exception e); protected virtual void UnloadContent();
Tramite questi eventi possiamo intervenire in diverse fasi dell'esecuzione del gioco:
Evento | Si scatena.. |
---|---|
BeginDraw | prima dell'invocazione di ciascuna Draw |
BeginRun | prima dell'avvio del main loop |
EndDraw | subito dopo ciascuna Draw |
EndRun | subito al termine del main loop |
OnActivated (e OnDeactivated) | all'attivazione e alla deattivazione della finestra, utile, ad esempio, per mettere il gioco in pausa |
OnExiting | quando l'applicazione inizia il processo di chiusura |
ShowMissingRequirementMessage | quando l'inizializzazione fallisce perché uno dei requisiti hardware di XNA non è rispettato |
Inoltre possiamo intervenire quando il game deve scaricare le risorse create in LoadContent
.
Abbiamo a disposizione anche alcuni eventi "tradizionali" di .Net, qualora preferiamo ascoltare quelli invece che effettuare l'overriding dei metodi corrispondenti:
public event EventHandler Activated;
public event EventHandler Deactivated;
public event EventHandler Disposed;
public event EventHandler Exiting;
Proprietà
Oltre agli eventi, possiamo ispezionare alcune proprietà generali del nostro game:
public LaunchParameters LaunchParameters { get; }
public bool IsActive { get; }
public GameWindow Window { get; }
In particolare possiamo:
- Ottenere i parametri con cui l'applicazione è stata lanciata (LaunchParameters)
- Investigare se l'applicazione è correntemente in evidenza sul desktop (IsActive)
- Manipolare la finestra dell'applicazione (Window)
Medodi
Infine abbiamo alcuni metodi con cui mandare istruzioni al game:
public void Exit();
public void Run();
public void RunOneFrame();
Le loro funzioni sono molto semplici:
Metodo | Descrizione |
---|---|
Exit | chiude il game terminandone il main loop |
Run | avvia il main loop |
RunOneFrame | esegue immediatamente una singola iterazione del main loop |
Questi sono, in sintesi gli strumenti che abbiamo a disposizione per intervenire sul gioco. Nella prossima lezione inizieremo ad esaminare i meccanismi che regolano il timing.