The Xna-Way: Tutorial 4: Input

Ok eccoci di nuovo qua.
Dopo aver visto la telecamera della scena, come si carica e renderizza un semplice modello voglio vedere ora come organizzare la gestione dell'input!

Come ho deciso di organizzare questa cosa?
Bè XNA ci da tutte le funzioni per gestire l'input da tastiera, da mouse e da gamePad. Come sempre lavoro solo su Windows, quindi io gestirò solo quello da mouse e da tastiera, anche se per ora mi dedicherò solo a quello da tastiera.

Lo stato della tastiera va aggiornato e controllato ad ogni ciclo di esecuzione, e il posto migliore per farlo è il metodo update.
Quindi posso pensare di organizzare un gameComponent per la gestione e aggiornamento dell'input da tastiera. Ma quanti e quali componenti devono/possono usare l'input?
Be così ad occhio io direi la nostra telecamera, e per ora un eventuale personaggio da muovere. Se poi ci fossero altri componenti potremmo avere dei problemi di accesso ai dati per l'input.
Sarebbe auspicabile che ogni componente che vuole accedere all'input acceda agli stessi dati, cioè alla stessa copia in memoria dei dati relativi all'input.

Come per la telecamera anche il gestore dell'input sarà visto come un servizio, al quale poi potremo accedere da ogni punto del nostro gioco.
Per fare questo quindi useremo un'interfaccia, che esporrà i metodi e le proprietà che ci servono, e una classe (un gameComponent) che implementi l'interfaccia.
L'interfaccia e la classe saranno rispettivamente InputI e MyInput.

Ecco il codice del file che andremo ad aggiungere alla nostra libreria di classi:
MyInput.cs
Show/Hide


Come sempre se in futuro ci servono nuove funzionalità esse verranno implementate, ma per ora non ci servono e basta quello che abbiamo.

Cosa fa il codice?
Bè la classe definisce un oggetto di tipo KeyboardState, il quale andrà a contenere lo stato della tastiera, è cioè quali sono i tasti premuni e non premuti.
Nel costrutture, come pensato, vado ad aggiungere il gameComponent alla lista dei Servizi.

Il metodo update fa una cosa semplicissima: ad ogni esecuzione aggiorna il valore attuale contenuto nella variabile kState, in modo che quando un altro componente vuole ottenere informazioni sulla tastiera otterrà sempre lo stato aggioranto.

Come posso recuperare il riferimento al servizio ed utilizzarlo?
Andiamo nella nostra classe Model3D, e andiamo ad aggiungere un campo di classe così:
InputI inputDevice;

che sarà usato per contenere il riferimento al nostro gestore dell'input.
Ne costruttore di Model3D andiamo ad aggiungere questa riga:
inputDevice = (InputI)game.Services.GetService(typeof(InputI));

è simile a quella usata per recuperare il riferimento al servizio che gestisce la telecamera, solo che questa recupera il servizio per l'output.
Nel metodo update della classe Model3D aggiugiamo queste righe sotto l'incremento dell'angolo sull'asse Y:
if(inputDevice.KeyBoardState.IsKeyDown(Keys.Up))
angleX += 5f * (float)gameTime.ElapsedRealTime.TotalSeconds;


in modo che quando premiamo il tasto "up" l'angolo sull'asse X venga incrementato.
Bene quasi finito!

Andiamo nel file Game1.cs, aggiungiamo anche qui il campo
inputDevice = (InputI)game.Services.GetService(typeof(InputI));

e il costruttore trasfromiamolo così:
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
counter = new FPSCounter(this);
Components.Add(counter);

myInput = new MyInput(this);
Components.Add(myInput);

myCamera = new Camera(this);
Components.Add(myCamera);
}

Come possiamo vedere ho creato ed aggiunto un oggetto di tipo MyInput alla collezione dei componenti.
Ma come mai l'ho fatto prima della telecamera?
Perchè se in un futuro amplierò le funzionalità della mia telecamera e vorrò usare l'input, se aggiungo prima la camera e poi l'input, quando nel costrutire la telecamera andrò a cercare di recuperare il riferimento al servizio che implementa l'interfaccia InputI mi ritornerà NULL, dato che tale servizio non sarà stato ancora aggiunto. Così facendo invece la telecamera lo troverebbe pronto.

Se ora avviamo il gioco, dovremmo vedere sempre il nostro asteroide che ruota, ma premendo il tasto SU ruoterà anche attorno all'asse X.
Fantastico! E anche molto semplice direi ^^

Bene facciamo un'ultima modifca e poi abbiamo finito per oggi!
Nel metodo update della classe Game1.cs andiamo ad eliminare la condizione del costrutto if (che riguarda il gamePad) con questa:
if (myInput.KeyBoardState.IsKeyDown(Keys.Escape))
this.Exit();


in modo che premendo il tasto Escape allora il gioco verrà terminato!

Ok per oggi è tutto!
Spero di essere stato chiaro.
Anche questa volta niente sorgenti, dato che il file per il componente di Input è tutto listato qua sopra, e le modifiche da fare sono esigue.

Se qualcosa non vi torna ditelo senza problemi e correggo! :)

Alla prossima!

0 commenti:

Donazioni

My Menu'