Posts tagged sdl
Mettiamo tutto insieme (Conclusioni) – Creazione di un gioco con SDL.NET
dic 5
In realtà sotto questo punto di vista c’è tanto da scrivere ma anche poco da scrivere: tanto perchè ci sarebbe innanzitutto da compilare il nostro codice. Una volta ottenuti gli eseguibili funzionanti dobbiamo avere una precisa struttura della cartella del nostro programma. Ed a questo, come avete visto, ci abbiamo pensato in precedenza.
Dobbiamo testare a fondo il gioco, in modo tale da notare rallentamenti (non in questo caso ovviamente). Nel caso ci sia qualcosa che non va, si riprende il codice e lo si modifica, si cercano degli errori. Certo, questo è facile da dire ma spesso è assolutamente stancante da fare nella pratica. Nonostante abbia fatto questo gioco in due giorni scarsi c’è da dire che non era tutto perfetto da subito: man mano che andavo avanti ho fatto prove, compilato, ricompilato e modificato per poi compilare nuovamente.
Niente perchè, appunto, è facile da scrivere ma difficile da fare.
Una grande fortuna, devo ammetterlo, è stato quello di poter lavorare con un linguaggio managed come il C#, eliminando in questo modo tutta una serie di problemi che si potevano presentare con un linguaggio si più efficace, ma altrettanto complesso come il C++.
Adesso che abbiamo la nostra struttura pronta, non dobbiamo fare altro che creare un programma di installazione per il nostro gioco: potrete scoprire come si fa leggendo l’articolo dedicato a questo scopo su questo stesso blog.
Grazie per l’ascolto!
Gestiamo l’Input. – Creazione di un gioco con SDL.NET
dic 5
Il gioco che stiamo creando, ovviamente, non va mica avanti da solo. Qualcuno deve far muovere le cose, fare in modo che determinati eventi e determinati spostamenti avvengano. Quel qualcuno è il nostro giocatore. Come già spiegato nella “guida base” l’input è gestito facilmente dalle librerie SDL e applicare questi concetti alla pratica sarà ancora più facile.
In tutta la struttura del gioco c’è solo un metodo che si occupa di prendere tutto l’input ed elaborarlo: il metodo Events_KeyboardDown. Ecco il codice, riproposto qui di seguito, che verrà successivamente commentato in modo da essere compreso in tutto e per tutto.
[code]]czoyNDcwOlwiDQpwcml2YXRlIHZvaWQgRXZlbnRzX0tleWJvYXJkRG93bihvYmplY3Qgc2VuZGVyLCBLZXlib2FyZEV2ZW50QXJncyB7WyYqJl19ZSkNCiAgICAgICAgew0KICAgICAgICAgICAgc3dpdGNoIChzdGF0bykNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICBjYXtbJiomXX1zZSBHYW1lU3RhdGUuSW50cm86DQogICAgICAgICAgICAgICAgICAgIGlmIChlLktleSA9PSBLZXkuUmV0dXJuKSBzdGF0byA9IEdhe1smKiZdfW1lU3RhdGUuR2FtZTsNCiAgICAgICAgICAgICAgICAgICAgaWYgKGUuS2V5ID09IEtleS5Fc2NhcGUpIHN0YXRvID0gR2FtZVN0YXR7WyYqJl19ZS5FeGl0Ow0KICAgICAgICAgICAgICAgICAgICBicmVhazsNCg0KICAgICAgICAgICAgICAgIGNhc2UgR2FtZVN0YXRlLkdhbWU6DXtbJiomXX0KICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKHN0YXRvX3ApDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5QcmltYToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGUuS2V7WyYqJl19eSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgS2V5LntbJiomXX1SZXR1cm46DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0b19wID0gU3RhdG9QYXJ0aXRhLkluQ29yc287e1smKiZdfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmVzZXRHYW1lKCk7DQoNCiAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgICBicmVhazsNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtleS5Fc2NhcGU6DQogIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdG8gPSBHYW1lU3RhdGUuRXhpdDsNCiAgICAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5JbkNvcnNvOg0KICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGUuS2V5KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsNCiAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgS2V5LkxlZnRBcnJvdzoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICBpZiAocG9zaXppb25lX2dpb2NhdG9yZSA+IDApIHBvc2l6aW9uZV9naW9jYXRvcmUtLTsNCiAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICBicmVhazsNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtleS5SaWdoe1smKiZdfXRBcnJvdzoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwb3NpemlvbmVfZ2lvY2F0b3JlIDwgcG9zaXp7WyYqJl19aW9uaV9naW9jYXRvcmUuQ291bnQgLSAxKSBwb3NpemlvbmVfZ2lvY2F0b3JlKys7DQogICAgICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBLZXkuRXNjYXBlOg0KICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlc2V0R2FtZSgpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgIHN0YXRvX3AgPSBTdGF0b1BhcnRpdGEuUHJpbWE7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3tbJiomXX07DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuRmluZToNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN7WyYqJl19d2l0Y2ggKGUuS2V5KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gIGNhc2UgS2V5LlJldHVybjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRvX3AgPSBTdGF0b1BhcnRpe1smKiZdfXRhLlByaW1hOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgIGNhc2UgS2V5LkVzY2FwZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRvID0gR3tbJiomXX1hbWVTdGF0ZS5FeGl0Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgfQ0KICB7WyYqJl19ICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICBjYXNlIEdhbWVTdGF0ZS5FeGl0Og0KDQogICAgICAgIHtbJiomXX0gICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfQ0KXCI7e1smKiZdfQ==[[/code]
Innanzitutto diamo uno sguardo ai parametri in input: c'è il sender, di tipo generico object, e la variabile “e” di tipo KeyboardEventArgs. Proprio quest'ultima variabile sarà il perno di tutto il metodo.
Prima di dare uno sguardo al codice, inoltre, ricordatevi sempre che stiamo ragionando in base agli stati: diverso è lo stato in cui il gioco si trova, diverse saranno le necessità a cui dovremo far fronte. In parole povere: ci troviamo nella schermata d'introduzione? Non ci sarà bisogno di gestire lo spostamento del personaggio. E così via discorrendo.
Di conseguenza opereremo in questo modo: creando prima uno switch che comprenda i casi di tutti gli stati, e per ognuno di essi effettuare operazioni diverse. Partiamo dal primo caso:
[code]]czoxOTM6XCINCmNhc2UgR2FtZVN0YXRlLkludHJvOg0KICAgICAgICAgICAgICAgICAgICBpZiAoZS5LZXkgPT0gS2V5LlJldHVybil7WyYqJl19IHN0YXRvID0gR2FtZVN0YXRlLkdhbWU7DQogICAgICAgICAgICAgICAgICAgIGlmIChlLktleSA9PSBLZXkuRXNjYXBlKSBzdGF0b3tbJiomXX0gPSBHYW1lU3RhdGUuRXhpdDsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQpcIjt7WyYqJl19[[/code]
Questo è sicuramente il caso più semplice. Fin quando il gioco si troverà nello stato Intro, verrà mostrato a schermo il background con le istruzioni del gioco, oltre ad un invito a premere invio per continuare. Dunque, sono due le cose che possiamo fare: o passiamo alla schermata di gioco oppure ce ne usciamo.
Qui arriva in nostro aiuto il parametro “e”. La proprietà e.Key, infatti, permette di sapere se in quel momento un determinato pulsante sulla tastiera è stato premuto. Il controllo, nella sua maniera più semplice, avviene con questa sintassi:
if (e.Key == Key.codice_chiave) // qui vanno le operazioni da eseguire.
Come potete vedere dall'intellisense, Key (e non e.Key, che è una proprietà) è un enumerazione comprendente tutti i caratteri della tastiera. Quindi ci basterà confrontare e.Key con un valore di Key per sapere se quel determinato pulsante è stato premuto.
Tornando al nostro codice, quindi, nella prima riga verifichiamo che il tasto invio venga premuto. Nel caso viene premuto (e l'uguaglianza ritorna true) allora lo stato viene modificato in GameState.Game. Se invece la condizione non è verificata tutto rimane come prima.
Nella seconda istruzione le cose sono simili: verifichiamo che il pulsante ESC venga premuto. Se si allora passeremo allo stato GameState.Exit, che provvederà a farci uscire dal programma. Altrimenti tutto rimarrà invariato e la schermata continuerà ad essere mostrata. Andiamo avanti col nostro codice.
[code]]czoyMDI2OlwiDQogY2FzZSBHYW1lU3RhdGUuR2FtZToNCiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChzdGF0b19wKQ0KICAgICB7WyYqJl19ICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuUHJpbWE6DQogICAgICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoZS5LZXkpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBLZXkuUmV0dXJuOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19IHN0YXRvX3AgPSBTdGF0b1BhcnRpdGEuSW5Db3JzbzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJlc2V0R3tbJiomXX1hbWUoKTsNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgIGNhc2UgS2V5LkVzY2FwZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRvID0gR2F7WyYqJl19bWVTdGF0ZS5FeGl0Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCg0KICAgICAgICAgICAgICAgICAgICAgICAge1smKiZdfWNhc2UgU3RhdG9QYXJ0aXRhLkluQ29yc286DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlLktleSkNCiAgICB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtleS5MZWZ0QXJyb3tbJiomXX13Og0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBvc2l6aW9uZV9naW9jYXRvcmUgPiAwKSBwb3Npemlve1smKiZdfW5lX2dpb2NhdG9yZS0tOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgICAgICAgIGNhc2UgS2V5LlJpZ2h0QXJyb3c6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gaWYgKHBvc2l6aW9uZV9naW9jYXRvcmUgPCBwb3NpemlvbmlfZ2lvY2F0b3JlLkNvdW50IC0gMSkgcG9zaXppb25lX2dpb2NhdG9ye1smKiZdfWUrKzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICBjYXNlIEtleS5Fc2NhcGU6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZXNldEdhbWUoKTsNCntbJiomXX0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0b19wID0gU3RhdG9QYXJ0aXRhLlByaW1hOw0KICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgU3RhdG9QYXJ0aXRhLkZpbmU6DXtbJiomXX0KDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlLktleSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e1smKiZdfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtleS5SZXR1cm46DQogICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgc3RhdG9fcCA9IFN0YXRvUGFydGl0YS5QcmltYTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gICBicmVhazsNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtleS5Fc2NhcGU6DQogICAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgc3RhdG8gPSBHYW1lU3RhdGUuRXhpdDsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYntbJiomXX1yZWFrOw0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KXCI7e1smKiZdfQ==[[/code]
Dunque, in questa parte di codice stiamo gestendo il caso dello stato GameState.Game. Ci troviamo nella schermata di gioco vera e propria e, quindi, è da qui che dobbiamo partire per gestire i vari stati in cui si trova la partita (la variabile stato_p).
Per questo apriamo un nuovo switch, stavolta prendendo in esame il valore della variabile, appunto, stato_p.
Nel primo caso il discorso è semplice: ci troviamo nella schermata in cui il gioco non ancora inizia e possiamo fare solo due cose: o premere invio per iniziare la partita, oppure premere esc per uscire dal gioco. In codice, ciò si traduce in:
[code]]czo1NDI6XCINCmNhc2UgU3RhdG9QYXJ0aXRhLlByaW1hOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoZS5LZXl7WyYqJl19KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBLZXkuUntbJiomXX1ldHVybjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRvX3AgPSBTdGF0b1BhcnRpdGEuSW5Db3JzbzsNe1smKiZdfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZXNldEdhbWUoKTsNCg0KICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgS2V5LkVzY2FwZToNCiAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0byA9IEdhbWVTdGF0ZS5FeGl0Ow0KICAgICAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgYnJlYWs7DQpcIjt7WyYqJl19[[/code]
Come potete vedere, al posto di fare più if ho fatto un altro blocco switch con i casi corrispondenti ai pulsanti che volevo gestire. Se premiamo invio lo stato della partita passa da "Prima" a "InCorso" e le statistiche di gioco vengono resettate tramite ResetGame(). Nel caso in cui venga premuto Esc, invece, c'è poco da dire: la variabile "stato" passa a GameState.Exit e usciremo dal gioco dopo gli opportuni passaggi.
Per il caso della partita in corso, invece, le cose da gestire sono giusto un paio in più.
[code]]czo3ODg6XCINCmNhc2UgU3RhdG9QYXJ0aXRhLkluQ29yc286DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlLkt7WyYqJl19ZXkpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIEtleXtbJiomXX0uTGVmdEFycm93Og0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBvc2l6aW9uZV9naW9jYXRvcmUgPiAwe1smKiZdfSkgcG9zaXppb25lX2dpb2NhdG9yZS0tOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgS2V5LlJpZ2h0QXJyb3c6DQogICAgICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICAgaWYgKHBvc2l6aW9uZV9naW9jYXRvcmUgPCBwb3NpemlvbmlfZ2lvY2F0b3JlLkNvdW50IC0gMSkgcG9zaXppb25le1smKiZdfV9naW9jYXRvcmUrKzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICAgICAgICAgICBjYXNlIEtleS5Fc2NhcGU6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSZXNldHtbJiomXX1HYW1lKCk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0b19wID0gU3RhdG9QYXJ0aXRhLlByaW1hOw0Ke1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQpcIjt7WyYqJl19[[/code]
Si fa il classico switch per vedere qualche tasto è stato premuto e ora i tasti da gestire sono tre: la freccia sinistra (Key.LeftArrow nella nostra enumerazione Key), la freccia destra (corrispondente a RightArrow) e il tasto Esc per uscire dalla partita in corso. Non è stata prevista una pausa durante il gioco.
E per ultimo gestiamo il caso della partita terminata:
[code]]czo0ODk6XCINCmNhc2UgU3RhdG9QYXJ0aXRhLkZpbmU6DQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGUuS2V7WyYqJl19eSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgS2V5LntbJiomXX1SZXR1cm46DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0b19wID0gU3RhdG9QYXJ0aXRhLlByaW1hOw0Ke1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICBjYXNlIEtleS5Fc2NhcGU6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0byA9IEdhbWVTdGF0ZS5FeHtbJiomXX1pdDsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAge1smKiZdfSB9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQpcIjt7WyYqJl19[[/code]
Non credo serva spiegare davvero quello che ho fatto, è lo stesso identico procedimento che ho adoperato per i due casi precedenti.
Bene, anche per l'input ci siamo e, a meno che non ci siamo scordati qualcosa in precedenza, il nostro gioco è praticamente completo a livello di codice. Adesso ci prepareremo per la compilazione, concludendo così l'ultimo articolo di questa serie di tutorials.
Disegnamo il Marito. – Creazione di un gioco con SDL.NET
dic 5
Dato che abbiamo voluto utilizzare tre immagini differenti per il marito, il discorso sarà leggermente diverso ma comunque niente di complesso. Il nostro codice mostra nuove aggiunte:
[code]]czoyMjQzOlwiDQpwcml2YXRlIHZvaWQgVXBkYXRlUGFydGl0YSgpDQogICAgICAgIHsNCiAgICAgICAgICAgIHN3aXRjaCAoc3RhdG97WyYqJl19X3ApDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuUHJpbWE6DQogICAgICAgICAgICAgIHtbJiomXX0gICAgICBWaWRlby5TY3JlZW4uQmxpdChiYWNrZyk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJle1smKiZdfW5kZXIoXCJQdW50ZWdnaW86IDBcIiwgU3lzdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNntbJiomXX0wLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlByZW1pIEludmlvIHBlciBpbntbJiomXX1pemlhcmUgbGEgcGFydGl0YS4uLlwiLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludHtbJiomXX0oNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlZpdGU6IDBcIiwgU3lzdGV7WyYqJl19bS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw0KICAgICAgICAgICAgICAgIHtbJiomXX0gICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5JbkNvcnNvOg0KICAgICAgICAgICAgICAgICAge1smKiZdfSAgVmlkZW8uU2NyZWVuLkJsaXQoYmFja2cpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXJ7WyYqJl19KFwiUHVudGVnZ2lvOiBcIiArIHB1bnRlZ2dpby5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0e1smKiZdfWVtLkRyYXdpbmcuUG9pbnQoNjAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZGVyKFwie1smKiZdfVZpdGU6IFwiICsgdml0ZS5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qe1smKiZdfW9pbnQoNDAwLCAyKSk7DQoNCgkgICAgIHN3aXRjaCAocG9zaXppb25lX2dpb2NhdG9yZSkNCiAgICAgICAgICAgICAgICAgICAgew17WyYqJl19CiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgMDoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQntbJiomXX1saXQoZ2lvYzEsIHBvc2l6aW9uaV9naW9jYXRvcmVbcG9zaXppb25lX2dpb2NhdG9yZV0pOw0KICAgICAgICAgICAgICAgICAgICAge1smKiZdfSAgICAgICBicmVhazsNCg0KICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAxOg0KICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICBWaWRlby5TY3JlZW4uQmxpdChnaW9jMiwgcG9zaXppb25pX2dpb2NhdG9yZVtwb3NpemlvbmVfZ2lvY2F0b3JlXSk7DQogICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDI6DQogICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGdpb2MzLCBwb3NpemlvbmlfZ2lvY2F0b3JlW3Bvc2l6aW9uZV9naW97WyYqJl19Y2F0b3JlXSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgICAgIH0NCg0KCSAgIHtbJiomXX0gICBWaWRlby5TY3JlZW4uQmxpdCh3aWZlLCBwb3NpemlvbmlfbW9nbGllW3Bvc2l6aW9uZV9tb2dsaWVdKTsNCiAgICAgICAgICAge1smKiZdfSAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuRmluZToNCiAgICAgICAgICAgICAgICB7WyYqJl19ICAgIFZpZGVvLlNjcmVlbi5CbGl0KGJhY2tnKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZHtbJiomXX1lcihcIlB1bnRlZ2dpbzogXCIgKyBwdW50ZWdnaW8uVG9TdHJpbmcoKSwgU3lzdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3l7WyYqJl19c3RlbS5EcmF3aW5nLlBvaW50KDYwLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcntbJiomXX0oXCJQYXJ0aXRhIFRlcm1pbmF0YSwgcHJlbWVyZSBJbnZpby4uLlwiLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN7WyYqJl19dGVtLkRyYXdpbmcuUG9pbnQoNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcntbJiomXX0oXCJWaXRlOiAwXCIsIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw17WyYqJl19CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICB9DQp9DQpcIjt7WyYqJl19[[/code]
Abbiamo inserito un altro switch, che stavolta serve a controllare sotto quale finestra si trova il giocatore: il metodo utilizzato ed il ragionamento alla base, però, sono gli stessi che abbiamo adottato per la moglie. Così, dopo aver controllato la posizione del giocatore tramite lo switch, ecco che utilizziamo l'istruzione
Video.Screen.Blit(gioc1, posizioni_giocatore[posizione_giocatore]);
oppure
Video.Screen.Blit(gioc2, posizioni_giocatore[posizione_giocatore]);
oppure
Video.Screen.Blit(gioc3, posizioni_giocatore[posizione_giocatore]);
In poche parole, cambia solo il nome della variabile. La cosa si complica un po' di più, invece, per ciò che concerne gli oggetti. Andiamo avanti per scoprire come.
Disegnamo la moglie. – Creazione di un gioco con SDL.NET
dic 5
Torniamo ad esaminare il codice di prima, facendo una piccola aggiunta in grassetto:
[code]]czoyMjQzOlwiDQpwcml2YXRlIHZvaWQgVXBkYXRlUGFydGl0YSgpDQogICAgICAgIHsNCiAgICAgICAgICAgIHN3aXRjaCAoc3RhdG97WyYqJl19X3ApDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuUHJpbWE6DQogICAgICAgICAgICAgIHtbJiomXX0gICAgICBWaWRlby5TY3JlZW4uQmxpdChiYWNrZyk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJle1smKiZdfW5kZXIoXCJQdW50ZWdnaW86IDBcIiwgU3lzdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNntbJiomXX0wLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlByZW1pIEludmlvIHBlciBpbntbJiomXX1pemlhcmUgbGEgcGFydGl0YS4uLlwiLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludHtbJiomXX0oNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlZpdGU6IDBcIiwgU3lzdGV7WyYqJl19bS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw0KICAgICAgICAgICAgICAgIHtbJiomXX0gICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5JbkNvcnNvOg0KICAgICAgICAgICAgICAgICAge1smKiZdfSAgVmlkZW8uU2NyZWVuLkJsaXQoYmFja2cpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXJ7WyYqJl19KFwiUHVudGVnZ2lvOiBcIiArIHB1bnRlZ2dpby5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0e1smKiZdfWVtLkRyYXdpbmcuUG9pbnQoNjAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZGVyKFwie1smKiZdfVZpdGU6IFwiICsgdml0ZS5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qe1smKiZdfW9pbnQoNDAwLCAyKSk7DQoNCgkgICAgIHN3aXRjaCAocG9zaXppb25lX2dpb2NhdG9yZSkNCiAgICAgICAgICAgICAgICAgICAgew17WyYqJl19CiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgMDoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQntbJiomXX1saXQoZ2lvYzEsIHBvc2l6aW9uaV9naW9jYXRvcmVbcG9zaXppb25lX2dpb2NhdG9yZV0pOw0KICAgICAgICAgICAgICAgICAgICAge1smKiZdfSAgICAgICBicmVhazsNCg0KICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAxOg0KICAgICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICBWaWRlby5TY3JlZW4uQmxpdChnaW9jMiwgcG9zaXppb25pX2dpb2NhdG9yZVtwb3NpemlvbmVfZ2lvY2F0b3JlXSk7DQogICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDI6DQogICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGdpb2MzLCBwb3NpemlvbmlfZ2lvY2F0b3JlW3Bvc2l6aW9uZV9naW97WyYqJl19Y2F0b3JlXSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgICAgIH0NCg0KCSAgIHtbJiomXX0gICBWaWRlby5TY3JlZW4uQmxpdCh3aWZlLCBwb3NpemlvbmlfbW9nbGllW3Bvc2l6aW9uZV9tb2dsaWVdKTsNCiAgICAgICAgICAge1smKiZdfSAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuRmluZToNCiAgICAgICAgICAgICAgICB7WyYqJl19ICAgIFZpZGVvLlNjcmVlbi5CbGl0KGJhY2tnKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZHtbJiomXX1lcihcIlB1bnRlZ2dpbzogXCIgKyBwdW50ZWdnaW8uVG9TdHJpbmcoKSwgU3lzdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3l7WyYqJl19c3RlbS5EcmF3aW5nLlBvaW50KDYwLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcntbJiomXX0oXCJQYXJ0aXRhIFRlcm1pbmF0YSwgcHJlbWVyZSBJbnZpby4uLlwiLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN7WyYqJl19dGVtLkRyYXdpbmcuUG9pbnQoNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcntbJiomXX0oXCJWaXRlOiAwXCIsIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw17WyYqJl19CiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICB9DQp9DQpcIjt7WyYqJl19[[/code]
L'istruzione evidenziata serve a disegnare la moglie nella posizione scelta dal sistema. Spieghiamola meglio:
La moglie può essere disegnata in tre posizioni differenti:
- alla finestra 1,
- alla finestra 2,
- alla finestra 3.
Queste tre posizioni sono identificabili come dei punti. Nel nostro caso, i punti sono:
- x = 151 – y = 71;
- x = 351 – y = 71;
- x = 551 – y = 71;
Abbiamo quindi creato una lista di punti (List, precisamente
): la lista “posizioni_moglie”. Ovviamente la moglie non può essere in tre luoghi contemporaneamente: la sua posizione attuale è regolata dalla variabile “posizione_moglie”, un intero che viene passato come indice della lista. Riguardate e capirete per bene:
Video.Screen.Blit(wife, posizioni_moglie[posizione_moglie]);
Con questa sola riga di codice disegneremo senza problemi la moglie.
Disegnamo il Background. – Creazione di un gioco con SDL.NET
dic 5
Un esempio di disegno già l’abbiamo visto nell’articolo precedente, con l’istruzione “Video.Screen.Blit(intro);”, disegnando appunto la schermata di intro del gioco. Le cose ovviamente non sono così semplici per quanto riguarda il disegno della schermata di gioco vero e proprio. Iniziamo quindi ad analizzare la funzione UpdatePartita(). Il codice completo sarà scaricabile a parte, qui invece inserirò solo le parti man mano necessarie.
Partiamo con:
[code]]czoxNTg2OlwiDQpwcml2YXRlIHZvaWQgVXBkYXRlUGFydGl0YSgpDQogICAgICAgIHsNCiAgICAgICAgICAgIHN3aXRjaCAoc3RhdG97WyYqJl19X3ApDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuUHJpbWE6DQogICAgICAgICAgICAgIHtbJiomXX0gICAgICBWaWRlby5TY3JlZW4uQmxpdChiYWNrZyk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJle1smKiZdfW5kZXIoXCJQdW50ZWdnaW86IDBcIiwgU3lzdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNntbJiomXX0wLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlByZW1pIEludmlvIHBlciBpbntbJiomXX1pemlhcmUgbGEgcGFydGl0YS4uLlwiLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludHtbJiomXX0oNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlZpdGU6IDBcIiwgU3lzdGV7WyYqJl19bS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw0KICAgICAgICAgICAgICAgIHtbJiomXX0gICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5JbkNvcnNvOg0KICAgICAgICAgICAgICAgICAge1smKiZdfSAgVmlkZW8uU2NyZWVuLkJsaXQoYmFja2cpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXJ7WyYqJl19KFwiUHVudGVnZ2lvOiBcIiArIHB1bnRlZ2dpby5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0e1smKiZdfWVtLkRyYXdpbmcuUG9pbnQoNjAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZGVyKFwie1smKiZdfVZpdGU6IFwiICsgdml0ZS5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qe1smKiZdfW9pbnQoNDAwLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KDQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnR7WyYqJl19aXRhLkZpbmU6DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGJhY2tnKTsNCiAgICAgICAgICAgICAgICAgIHtbJiomXX0gIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlB1bnRlZ2dpbzogXCIgKyBwdW50ZWdnaW8uVG9TdHJpbmcoKSwgU3lzdGVtLkR7WyYqJl19cmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDYwLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIHtbJiomXX1WaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJQYXJ0aXRhIFRlcm1pbmF0YSwgcHJlbWVyZSBJbnZpby4uLlwiLCBTeXN0ZW0uRHJ7WyYqJl19YXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIHtbJiomXX1WaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJWaXRlOiAwXCIsIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3R7WyYqJl19ZW0uRHJhd2luZy5Qb2ludCg0MDAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICB9DQp9DQpcIjt7WyYqJl19[[/code]
Come potete vedere qui gestiamo ogni possibile caso per la variabile stato_p. Come ben sappiamo può assumere tre valori: Prima, InCorso (precedentemente detto Durante) e Fine. All'inizio, infatti, il gioco è fermo: dovremo premere invio per iniziare la nostra partita.
[code]]czo1MTA6XCINCmNhc2UgU3RhdG9QYXJ0aXRhLlByaW1hOg0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChiYWN7WyYqJl19a2cpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJQdW50ZWdnaW86IDBcIiwgU3lzdGVte1smKiZdfS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDYwLCAyKSk7DQogICAgICAgICAgICAgICAgICB7WyYqJl19ICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJQcmVtaSBJbnZpbyBwZXIgaW5pemlhcmUgbGEgcGFydGl0YS4uLlwiLCBTeXN0e1smKiZdfWVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNjAsIDE3KSk7DQogICAgICAgICAgICAgICB7WyYqJl19ICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJWaXRlOiAwXCIsIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3e1smKiZdfSBTeXN0ZW0uRHJhd2luZy5Qb2ludCg0MDAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQpcIjt7WyYqJl19[[/code]
Ecco cosa facciamo in ordine:
Disegnamo il nostro background, contenuto nella variabile backg;
- Scriviamo a schermo il punteggio, uguale a zero. L'istruzione che usiamo è Video.Screen.Blit che prende come parametro la funzione Render dell'oggetto font f1 precendetemente istanziato.
Domanda: perchè queste funzioni annidate?
Risposta: Innanzitutto, tramite l'intellisense scorri le varie proprietà e metodi dell'oggetto f1. Scoprirai che Render() restituisce una Surface
Per questo motivo è tranquillamente disegnabile tramite Blit().
Con lo stesso metodo del punto precedente disegnamo una scritta per invitare il giocatore a premere invio.
In egual modo scriviamo a schermo il numero delle vite, attualmente pari a 0 in quanto il gioco non ancora inizia.
Dovrebbe essere di facile comprensione
Ma andiamo avanti e leggiamo il codice scritto successivamente:
[code]]czozOTg6XCINCmNhc2UgU3RhdG9QYXJ0aXRhLkluQ29yc286DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGJ7WyYqJl19YWNrZyk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlB1bnRlZ2dpbzogXCIgKyBwdW50e1smKiZdfWVnZ2lvLlRvU3RyaW5nKCksIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDYwLCB7WyYqJl19MikpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJWaXRlOiBcIiArIHZpdGUuVG9TdHJpe1smKiZdfW5nKCksIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw0KICAgICB7WyYqJl19ICAgICAgICAgICAgICAgYnJlYWs7DQoNClwiO3tbJiomXX0=[[/code]
Dato che per adesso disegnamo solo il nostro background, la struttura del codice è simile al caso precedente. L'unica differenza è che non ci sarà, ovviamente, la scritta “Premi Invio per iniziare la partita...” e del punteggio e delle vite scriveremo il valore attuale, contenuto nelle variabili intere “punteggio” e “vite”.
Dopo aver spiegato questi due casi il codice del caso StatoPartita.Fine è di facilissima comprensione, per cui non mi dilungherò ulteriormente.
Che struttura avrà il codice? – Creazione di un gioco con SDL.NET
dic 4
Andando a scrivere il codice, dobbiamo ragionare sul modo in cui lo scriviamo. Come ho già spiegato precedentemente, il metodo che viene eseguito ad ogni frame è quello associato all’evento Tick. Inoltre, analizzando il file Template.Cs (file che ho usato come scheletro per il progetto) abbiamo visto due metodi private:
- AddHandlers()
- RemoveHandlers()
Questi due metodi, rispettivamente, aggiungono e rimuovono gli handlers al programma. La loro utilità è indubbia, specie in casi magari un pò più complicati di questo. Ecco il codice dei due metodi:
[code]]czo1Nzk6XCINCnByaXZhdGUgdm9pZCBBZGRIYW5kbGVycygpDQp7DQogICAgICAgICAgICBFdmVudHMuUXVpdCArPSBuZXcgRXZlbnR7WyYqJl19SGFuZGxlcjxRdWl0RXZlbnRBcmdzPih0aGlzLkV2ZW50c19RdWl0KTsNCiAgICAgICAgICAgIEV2ZW50cy5LZXlib2FyZERvd24gK3tbJiomXX09IG5ldyBFdmVudEhhbmRsZXI8S2V5Ym9hcmRFdmVudEFyZ3M+KEV2ZW50c19LZXlib2FyZERvd24pOw0KICAgICAgICAgICAgRXZle1smKiZdfW50cy5UaWNrICs9IG5ldyBFdmVudEhhbmRsZXI8VGlja0V2ZW50QXJncz4odGhpcy5FdmVudHNfVGljayk7DQp9DQoNCnByaXZhdGV7WyYqJl19IHZvaWQgUmVtb3ZlSGFuZGxlcnMoKQ0Kew0KICAgICAgICAgICAgRXZlbnRzLlF1aXQgLT0gbmV3IEV2ZW50SGFuZGxlcjxRdWl0RXtbJiomXX12ZW50QXJncz4odGhpcy5FdmVudHNfUXVpdCk7DQogICAgICAgICAgICBFdmVudHMuS2V5Ym9hcmREb3duIC09IG5ldyBFdmVudEhhe1smKiZdfW5kbGVyPEtleWJvYXJkRXZlbnRBcmdzPihFdmVudHNfS2V5Ym9hcmREb3duKTsNCiAgICAgICAgICAgIEV2ZW50cy5UaWNrIC09IG57WyYqJl19ZXcgRXZlbnRIYW5kbGVyPFRpY2tFdmVudEFyZ3M+KHRoaXMuRXZlbnRzX1RpY2spOw0KfQ0KXCI7e1smKiZdfQ==[[/code]
Pensate per esempio ad un insieme di menù o di schermate di gioco. Passando un parametro ad un ipotetico metodo di gestione degli handlers sarà possibile rimuoverli ed aggiungerli in base alle necessità, cosa decisamente ordinata.
Ma torniamo a noi, non complichiamoci la vita. Rimaniamo sul semplice. Come prima cosa analizziamo il costruttore della classe Template, quella principale.
[code]]czoxMTQ5OlwiDQpwdWJsaWMgVGVtcGxhdGUoKQ0KICAgICAgICB7DQogICAgICAgICAgICBwb3NpemlvbmlfZ2lvY2F0b3JlLkFkZCh7WyYqJl19bmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDE1MCwgNDUwKSk7DQogICAgICAgICAgICBwb3NpemlvbmlfZ2lvY2F0b3JlLkFkZChuZXtbJiomXX13IFN5c3RlbS5EcmF3aW5nLlBvaW50KDM1MCwgNDUwKSk7DQogICAgICAgICAgICBwb3NpemlvbmlfZ2lvY2F0b3JlLkFkZChuZXcge1smKiZdfVN5c3RlbS5EcmF3aW5nLlBvaW50KDU1MCwgNDUwKSk7DQoNCiAgICAgICAgICAgIHBvc2l6aW9uaV9tb2dsaWUuQWRkKG5ldyBTeXN7WyYqJl19dGVtLkRyYXdpbmcuUG9pbnQoMTUxLCA3MSkpOw0KICAgICAgICAgICAgcG9zaXppb25pX21vZ2xpZS5BZGQobmV3IFN5c3RlbS5EcntbJiomXX1hd2luZy5Qb2ludCgzNTEsIDcxKSk7DQogICAgICAgICAgICBwb3NpemlvbmlfbW9nbGllLkFkZChuZXcgU3lzdGVtLkRyYXdpbmcue1smKiZdfVBvaW50KDU1MSwgNzEpKTsNCg0KICAgICAgICAgICAgcG9zaXppb25pX2ZpbmVzdHJhMS5BZGQobmV3IFN5c3RlbS5EcmF3aW5nLlB7WyYqJl19b2ludCgxNTEsIDE2MSkpOw0KICAgICAgICAgICAgcG9zaXppb25pX2ZpbmVzdHJhMS5BZGQobmV3IFN5c3RlbS5EcmF3aW5nLlBvaXtbJiomXX1udCgxNTEsIDI1NSkpOw0KICAgICAgICAgICAgcG9zaXppb25pX2ZpbmVzdHJhMS5BZGQobmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50e1smKiZdfSgxNTEsIDM1MSkpOw0KDQogICAgICAgICAgICBwb3NpemlvbmlfZmluZXN0cmEyLkFkZChuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnR7WyYqJl19KDM1MSwgMTYxKSk7DQogICAgICAgICAgICBwb3NpemlvbmlfZmluZXN0cmEyLkFkZChuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoM3tbJiomXX01MSwgMjU1KSk7DQogICAgICAgICAgICBwb3NpemlvbmlfZmluZXN0cmEyLkFkZChuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoMzUxe1smKiZdfSwgMzUxKSk7DQoNCiAgICAgICAgICAgIHBvc2l6aW9uaV9maW5lc3RyYTMuQWRkKG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludCg1NTF7WyYqJl19LCAxNjEpKTsNCiAgICAgICAgICAgIHBvc2l6aW9uaV9maW5lc3RyYTMuQWRkKG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludCg1NTEsIHtbJiomXX0yNTUpKTsNCiAgICAgICAgICAgIHBvc2l6aW9uaV9maW5lc3RyYTMuQWRkKG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludCg1NTEsIDM1e1smKiZdfTEpKTsNCiAgICAgICAgfQ0KXCI7e1smKiZdfQ==[[/code]
Che diamine vuol dire tutto questo compendio di numeri e punti? E' presto detto: vi ricordate quando vi ho spiegato che marito, moglie ed oggetti sarebbero stati sempre disegnati in punti ben precisi, proprio come i vecchi giochini?
Pensate agli insiemi. Per quanto riguarda "posizione_giocatore" stiamo aggiungendo alla lista tutte le posizioni possibili che egli può assumere durante il gioco. Ad intuito è facile capire che lo spostamento avviene solo sull'asse X e non su Y, che rimane fissa a 450. Idem per quanto riguarda la moglie, che si sposta da 151 a 551 ma rimanendo sempre ad Y = 71.
Il discorso inverso invece viene fatto per gli oggetti: come potete vedere la X rimane uguale per ogni finestra (la finestra 1 avrà un x pari a 151, la finestra 2 invece pari a 351 e.c.c). Se ci fate caso, ovviamente la x delle finestre è uguale a alle x della moglie: questo perchè disegneremo i nostri oggetti sotto la moglie, in quanto lanciati da lei.
Dopo aver assegnato i punti proseguiamo con lo studio del nostro codice: adesso soffermiamoci un minuto sul metodo Main:
[code]]czo5NTpcIg0KW1NUQVRocmVhZF0NCnB1YmxpYyBzdGF0aWMgdm9pZCBNYWluKCkNCnsNCglUZW1wbGF0ZSBnYW1lID0gbmV3IFRlbXB7WyYqJl19bGF0ZSgpOw0KCWdhbWUuR28oKTsNCn0NClwiO3tbJiomXX0=[[/code]
Questo metodo fa due cose, e anche molto semplici: crea un'istanza della classe Template (quella che stiamo scrivendo) ed avvia il metodo Go() di questa. Il “[STAThread]” prima del metodo specifica il modello di Threading da utilizzare. Il metodo Main in se, comunque, è molto importante perchè è il punto d'ingresso della nostra applicazione: tutto parte da qua.
Adesso passiamo a Go():
[code]]czozNzI6XCINCnB1YmxpYyB2b2lkIEdvKCkNCnsNCiAgICAgICAgICAgIFZpZGVvLldpbmRvd0NhcHRpb24gPSBcIkEgR2FtZSBBYm91e1smKiZdfXQgV2lmZVwncyBGdXJ5LlwiOw0KICAgICAgICAgICAgVmlkZW8uU2V0VmlkZW9Nb2RlKDgwMCwgNjAwKTsNCiAgICAgICAgICAgIEV2ZXtbJiomXX1udHMuRnBzID0gNjA7DQoNCiAgICAgICAgICAgIHNvdHRvZm9uZG8uVm9sdW1lID0gMTA7DQogICAgICAgICAgICBzMS5Wb2x1bWUge1smKiZdfT0gMTA7DQogICAgICAgICAgICBzMi5Wb2x1bWUgPSAxMDsNCg0KICAgICAgICAgICAgc290dG9mb25kby5QbGF5KHRydWUpOw0KICB7WyYqJl19ICAgICAgICAgIA0KICAgICAgICAgICAgdGhpcy5BZGRIYW5kbGVycygpOw0KICAgICAgICAgICAgRXZlbnRzLlJ1bigpOw0KfQ0KXCJ7WyYqJl19O3tbJiomXX0=[[/code]
Bene, qui troviamo un po di cosette da analizzare: innanzitutto parliamo delle prime due istruzioni, dedicate all'oggetto Video: nella prima impostiamo il valore della proprietà WindowCaption, ovvero il titolo. Fin qui dovrebbe essere tranquillo. Altrettanto tranquillo per la seconda istruzione: con SetVideoMode impostiamo la risoluzione ad 800 x 600, passando come parametro i due interi che ci interessano.
Ecco un'istruzione importantissima:
Events.Fps = 60;
Mi raccomando, è indispensabile che gli Fps siano impostati a 60, dato che in precedenza abbiamo fatto tutto il discorso sulle variabili frames e framelimit. Assegnando il valore 60 a questa proprietà faremo in modo che il sistema generi precisamente 60 frames al secondo, proprio quello di cui abbiamo bisogno.
Dopo ciò troviamo tre istruzioni dedicate al sonoro: in questo caso ho impostato a 10 il valore sia della musica di sottofondo che delle variabili s1 ed s2, quelle che mantengono le informazioni dei suoni del bip e del bip più basso, usato in caso di perdita di una vita.
Domanda forse lecita: se avevi problemi con il volume della musica e non hai utilizzato una variabile di tipo Music, perchè mai ora hai impostato tutto a 10 e bon?
Risposta: semplicemente perchè a mio parere mi sembrava tutto troppo alto e quindi fastidioso
una volta provata la seconda strada, ovvero l'usare Sound anziché Music, il livello del volume era accettabile
Andando avanti, incontriamo l'istruzione “sottofondo.Play(true);”. Qui abbiamo semplicemente detto al programma di avviare la riproduzione della musica, in quanto verrà utilizzata in tutto il gioco fino alla sua chiusura. Il “true” passato come parametro indica che il loop del suono sarà infinito. E' la nostra unica musica, quindi la useremo sempre e senza complicarci la vita.
Dopo aver impostato tutti questi “piccoli” aspetti, possiamo procedere all'esecuzione di due metodi molto importanti. Con AddHandlers() gestiremo tutti gli eventi e con Run() daremo il via al main loop del sistema. In questo preciso istante il gioco è partito.
Tra gli altri metodi degni di nota troviamo ResetGame():
[code]]czoxNjk6XCINCnByaXZhdGUgdm9pZCBSZXNldEdhbWUoKQ0KICAgICAgICB7DQogICAgICAgICAgICBwb3NpemlvbmVfZ2lvY2F0b3J7WyYqJl19ZSA9IDA7DQogICAgICAgICAgICB2aXRlID0gMzsNCiAgICAgICAgICAgIHB1bnRlZ2dpbyA9IDA7DQogICAgICAgICAgICBmcmFtZXtbJiomXX1saW1pdCA9IDYwOw0KICAgICAgICB9DQpcIjt7WyYqJl19[[/code]
questo codice, di facile comprensione, verrà eseguito ogni volta che l'utente vorrà iniziare una nuova partita, reimpostando i punti a 0 e le vite a 3.
L’Importanza delle Enumerazioni. – Creazione di un gioco con SDL.NET
dic 4
Nell’articolo precedente, illustrando le variabili utilizzate nel gioco, avevo parlato di due di queste, rispettivamente “stato” e “stato_p”. stato è una variabile di tipo GameState. stato_p, invece, è una variabile di tipo StatoPartita. Questi due “tipi” sono delle enumerazioni.
Cos’è un enumerazione, e perchè è così importante? In realtà se state dando un occhiata alla programmazione di giochi dovreste saperlo, però due paroline le spendo volentieri. Stando alla cara MSDN, ecco una dritta:
C# consente di creare il proprio set di costanti denominate utilizzando la parola chiave enum. Questi tipi di dati consentono di dichiarare un set di nomi o di altri valori letterali che definiscono tutti i valori possibili assegnabili a una variabile.
Questo è un ottimo modo per rendere l’idea degli Stati in cui il gioco si trova. Nel mio caso, per esempio, ecco il codice delle enumerazioni, contenute nel file Utils.Cs.
[code]]czoyNzc6XCINCnVzaW5nIFN5c3RlbTsNCnVzaW5nIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljOw0KdXNpbmcgU3lzdGVtLlRleHR7WyYqJl19Ow0KDQpuYW1lc3BhY2UgQUdBV0YNCnsNCiAgICBwdWJsaWMgZW51bSBHYW1lU3RhdGUNCiAgICB7DQogICAgICAgIEludHJvLA0KIHtbJiomXX0gICAgICAgR2FtZSwNCiAgICAgICAgRXhpdA0KICAgIH0NCg0KICAgIHB1YmxpYyBlbnVtIFN0YXRvUGFydGl0YQ0KICAgIHsNCiAge1smKiZdfSAgICAgIFByaW1hLA0KICAgICAgICBJbkNvcnNvLA0KICAgICAgICBGaW5lDQogICAgfQ0KfQ0KXCI7e1smKiZdfQ==[[/code]
Come potete vedere, ho creato due enumerazioni. Una per lo stato del gioco (il gioco comprende sia la schermata iniziale che la schermata di gioco) ed una per lo stato della partita (che serve a determinare se la partita sta per iniziare, è in corso o è finita).
In questo modo, passando da un valore all'altro di un enumerazione, potremo scegliere cosa disegnare a schermo e cosa no. Per fare un esempio pratico, in GameState.Game non disegneremo mai la schermata di introduzione. Con lo stesso ragionamento, per esempio, non ci sogneremmo mai di disegnare a schermo il testo “Premi Invio per Iniziare” una volta che la partita è in corso.
Un aiuto non indifferente, sempre meglio che utilizzare degli int per indicare gli stati come facevo nei programmi del terzo superiore
Definiamo le nostre variabili. – Creazione di un gioco con SDL.NET
dic 4
Per la prima volta in questa guida iniziamo a vedere un pò di codice. Era pure ora. Per prima cosa apriamo il nostro ambiente di sviluppo e, se usiamo il caro Visual C# Express, possiamo anche utilizzare il comodo template di progetto che ho caricato sul sito qualche giorno fa.
Con la nostra finestra aperta e il sistema pronto, possiamo iniziare ad aggiungere queste righe di codice appena dopo l’inizio della classe principale, ovvero:
[code]]czoyMjU6XCINCnVzaW5nIFN5c3RlbTsNCnVzaW5nIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljOw0KDQp1c2luZyBTZGxEb3ROZXR7WyYqJl19LkNvcmU7DQp1c2luZyBTZGxEb3ROZXQuR3JhcGhpY3M7DQp1c2luZyBTZGxEb3ROZXQuSW5wdXQ7DQp1c2luZyBTZGxEb3ROZXQuQXtbJiomXX11ZGlvOw0KDQpuYW1lc3BhY2UgQUdBV0YNCnsNCiAgICBwdWJsaWMgY2xhc3MgVGVtcGxhdGUNCiAgICB7DQoJU0NSSVZJQU1PIFFVe1smKiZdfUkhDQpcIjt7WyYqJl19[[/code]
Ecco le nostre prime istruzioni:
GameState stato = GameState.Intro;
StatoPartita stato_p = StatoPartita.Prima;
Surface intro = new Surface("immagini/intro.jpg");
Surface backg = new Surface("immagini/back.jpg");
Surface gioc1 = new Surface("immagini/gioc1.png");
Surface gioc2 = new Surface("immagini/gioc2.png");
Surface gioc3 = new Surface("immagini/gioc3.png");
Surface wife = new Surface("immagini/wife.png");
Sound sottofondo = new Sound("musica/music1.ogg");
Sound s1 = new Sound("suoni/s1.wav");
Sound s2 = new Sound("suoni/s2.wav");
int frames = 0;
int framelimit = 60;
Font f1 = new Font("fonts/font1.ttf", 12);
int vite, punteggio;
List<System.Drawing.Point> posizioni_giocatore = new List<System.Drawing.Point>();
int posizione_giocatore = 0;
List<System.Drawing.Point> posizioni_moglie = new List<System.Drawing.Point>();
int posizione_moglie = 0;
List<System.Drawing.Point> posizioni_finestra1 = new List<System.Drawing.Point>();
List<System.Drawing.Point> posizioni_finestra2 = new List<System.Drawing.Point>();
List<System.Drawing.Point> posizioni_finestra3 = new List<System.Drawing.Point>();
List<OggettoCadente> oggetti = new List<OggettoCadente>();
Random r1 = new Random();
Non vi preoccupate se non capite qualcosa! Piano piano analizzeremo riga per riga e vedremo a cosa serve. Iniziamo dalle prime due: abbiamo le variabili stato e stato_p, che come specificato precedentemente serviranno a visualizzare e ad impostare lo stato attuale del gioco e della partita. Le due variabili sono di tipo GameState e StatoPartita: dopo questo articolo daremo un occhiata per bene all'utilità di queste enumerazioni.
Dopodichè abbiamo le seguenti istruzioni:
Surface intro = new Surface("immagini/intro.jpg");
Surface backg = new Surface("immagini/back.jpg");
Surface gioc1 = new Surface("immagini/gioc1.png");
Surface gioc2 = new Surface("immagini/gioc2.png");
Surface gioc3 = new Surface("immagini/gioc3.png");
Surface wife = new Surface("immagini/wife.png");
In questo blocco ho messo tutte le immagini che mi potevano servire per il gioco. La prima, intro, si collega ad intro.jpg nella cartella immagini. Lo stesso ragionamento vale per le altre ed in questo modo abbiamo in memoria tutti i files grafici che ci servono. Due parole vanno spese per le variabili gioc1, gioc2, gioc3. In realtà avrei potuto usare altri metodi per gestire il giocatore. Magari usare una sola variabile e ad ogni spostamento caricare il file corrispondente. Stavolta, però, ho voluto “sprecare” spazio ed utilizzare tre variabili distinte.
Si noti inoltre che a volte (non in questo caso ovviamente) caricare un memoria un file grafico può essere pesante. Non tutti i files grafici dei giochi, infatti, sono leggeri come questi!
Ora dobbiamo caricare in memoria i suoni: ecco le istruzioni che ci servono per rendere ciò possibile:
Sound sottofondo = new Sound("musica/music1.ogg");
Sound s1 = new Sound("suoni/s1.wav");
Sound s2 = new Sound("suoni/s2.wav");
In sottofondo abbiamo messo la musichetta di sottofondo e in s1 ed s2 i due effetti sonori, il bip e il bip del personaggio che perde una vita. Può sorgere spontanea una domanda: perchè, se esiste la classe Music, ho messo un file musicale come Sound? Semplicemente perchè possiamo deciderne il volume.
Nelle prime prove, infatti, avevo usato la classe Music, ma ben presto mi ero accorto che il volume della musica sovrastava il suono del bip di troppo e diventava quasi fastidioso. Usando invece la classe Sound potevo gestire il volume a mio piacimento. A domanda risposta
int frames = 0;
int framelimit = 60;
Queste due variabili di tipo Int sono il cuore del “timer” che avevo anticipato negli appunti. La variabile “frames” provvederà a contare il numero di frames passati e “framelimit”, come suggerisce il nome, rappresenta il valore numerico che la variabile “frames” deve raggiungere. A quel punto scateneremo gli eventi rispettivi.
Ma di questo parleremo più avanti: per adesso vediamo il codice delle definizioni delle variabili.
Per questo c'è bisogno di poche presentazioni:
Font f1 = new Font("fonts/font1.ttf", 12);
Abbiamo già visto nella guida base che questa è una semplice istruzione per caricare in memoria un Font chiamato f1, situato nella cartella fonts. La grandezza del carattere è specificata nel secondo parametro del costruttore (nel nostro caso 12).
Le variabili:
int vite, punteggio;
sono, rispettivamente, il numero delle vite del personaggio (che avranno un valore possibile da 3 a 0) e il punteggio del giocatore.
List<System.Drawing.Point> posizioni_giocatore = new List<System.Drawing.Point>();
int posizione_giocatore = 0;
Come detto in fase di “appunti” i personaggi che disegneremo verranno disegnati su punti dalle coordinate ben precise. A questo serve la nostra List “posizioni_giocatore”. In questo modo potremo memorizzare le coordinate che ci servono e, usando una variabile indice (guarda caso l'intero “posizione_giocatore”) disegneremo di volta in volta il giocatore in base alla sua posizione.
Stesso discorso, ovviamente, vale per la moglie: anche in questo caso infatti abbiamo dichiarato le variabili
List<System.Drawing.Point> posizioni_moglie = new List<System.Drawing.Point>();
int posizione_moglie = 0;
La prima consentirà di specificare tutte le posizioni della moglie (ambigua questa) mentre la seconda ci permetterà di volta in volta di disegnare in modo preciso la Surface. Il come tutto ciò avviene ve lo spiegherò dopo: guardate innanzitutto per bene il tipo di variabili che utilizziamo.
Abbiamo ancora alcuni punti da definire, e per questo motivo definiamo altre tre liste che ci accompagneranno nello sviluppo del gioco:
List<System.Drawing.Point> posizioni_finestra1 = new List<System.Drawing.Point>();
List<System.Drawing.Point> posizioni_finestra2 = new List<System.Drawing.Point>();
List<System.Drawing.Point> posizioni_finestra3 = new List<System.Drawing.Point>();
queste variabili servono a definire tutte le possibili posizioni che ogni oggetto cadente potrà assumere nel gioco. “posizioni_finestra1”, per esempio, servirà a specificare tutti i possibili punti che verranno utilizzati per disegnare un oggetto in caduta sotto la finestra numero uno (quella più a sinistra, per intenderci). Lo stesso discorso ovviamente vale per le altre finestre.
Infine, dobbiamo pure mettere da qualche parte i nostri oggetti. Ecco quindi che in soccorso arriva un'altra lista:
List<OggettoCadente> oggetti = new List<OggettoCadente>();
Come potete vedere in questo caso non abbiamo un tipo già definito di oggetto, in questa lista. Per l'oggetto che cade, infatti, avevamo deciso di utilizzare una classe a parte, chiamata OggettoCadente. Avevamo dato un occhiata ad una struttura generica di come poteva essere, ora vi mostro il codice per intero.
[code]]czo0NTk6XCINCnVzaW5nIFN5c3RlbTsNCnVzaW5nIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljOw0KDQp1c2luZyBTZGxEb3ROZXR7WyYqJl19LkNvcmU7DQp1c2luZyBTZGxEb3ROZXQuR3JhcGhpY3M7DQoNCm5hbWVzcGFjZSBBR0FXRg0Kew0KICAgIGNsYXNzIE9nZ2V0dG9DYXtbJiomXX1kZW50ZQ0KICAgIHsNCiAgICAgICAgcHVibGljIFN1cmZhY2UgQ2FudmFzOw0KDQogICAgICAgIHB1YmxpYyBpbnQgcG9zaXppb25le1smKiZdfTsNCiAgICAgICAgcHVibGljIGludCBmaW5lc3RyYTsNCg0KICAgICAgICBwdWJsaWMgT2dnZXR0b0NhZGVudGUoaW50IGYsaW50IHR7WyYqJl19KQ0KICAgICAgICB7DQogICAgICAgICAgICBDYW52YXMgPSBuZXcgU3VyZmFjZShcImltbWFnaW5pL1wiICsgdC5Ub1N0cmluZygpICsge1smKiZdfVwiLnBuZ1wiKTsNCiAgICAgICAgICAgIHBvc2l6aW9uZSA9IDA7DQogICAgICAgICAgICBmaW5lc3RyYSA9IGY7DQogICAgICAgIH0NCntbJiomXX0gICAgfQ0KfQ0KXCI7e1smKiZdfQ==[[/code]
Com'è facile notare non c'è molto di complicato, in realtà. Ogni istanza di questa classe avrà una propria Surface (che sarà quello che disegneremo), una finestra (in questo modo sapremo sotto quale finestra dovremo disegnare l'oggetto) e la posizione (in modo tale da gestire la caduta).
Il metodo costruttore, infine, che prende come parametri sia il tipo che il numero della finestra, esegue poche e semplici operazioni: carica in memoria il file corrispondente partendo dal tipo, assegna il valore 0 alla variabile posizione (l'oggetto sempre dall'alto dovrà partire) ed infine il numero della finestra.
Nota: il codice di OggettoCadente si trova in un file a parte, OggettoCadente.cs.
Infine, ecco l'ultima variabile che ci si presenta:
Random r1 = new Random();
Come ben sappiamo, la finestra da cui ogni oggetto dovrà cadere sarà decisa a caso di volta in volta. Per questo motivo ci è molto utile (per non dire indispensabile) una variabile di tipo Random.
Detto questo abbiamo terminato il nostro discorso sulle variabili. Come abbiamo visto, alcune volte potevamo fare delle ottimizzazioni: non c'è bisogno che vi dica di effettuare sempre scelte oculate in termini di variabili.
Certo, in un caso come questo una variabile in più o in meno non fa mai tutta questa differenza. Ma pensate ad un grande progetto, in cui centinaia e centiniaia di variabili vengono cambiate ogni millisecondo. Lì bisogna stare attentissimi a ciò che si fa.
Con ciò vi saluto e... al prossimo articolo!
La Struttura dei Files – Creazione di un gioco con SDL.NET
dic 4
Abbiamo raccolto le prime idee, le abbiamo messe sulla carta ed abbiamo creato un qualcosa di fattibile. Bene, adesso dobbiamo iniziare la fase di realizzazione vera e propria.. ma da dove partire? Innanzitutto, in questo articolo vedremo un pò la suddivisione dei files.
Molti demo, a volte, mettono i files che usano nella stessa cartella dell’exe. Questo va bene, appunto, per le demo, ma quando si crea un gioco? Conviene raggruppare tutto in cartelle in base a dei criteri scelti dall’utente. Nel mio caso non ho voluto complicare chissà quanto le cose, ed ho così pensato alla struttura delle cartelle del gioco:
Cartella di Gioco
- fonts/
- immagini/
- musica/
- suoni/
e poi tutti i files dll e l’eseguibile del nostro gioco. In questo modo le cose iniziano a filare. In realtà, ripensandoci mentre scrivo queste righe, potevo pure evitarmi di differenziare le cartelle “musica” e “suoni”.
E’ davvero inutile che mi dilunghi troppo in questo articolo, in quanto ognuno può trarre i vantaggi che vuole da una struttura del genere dei files e delle cartelle. Per cui andiamo avanti ed iniziamo a parlare di codice vero e proprio!
Appunti e Controappunti – Creazione di un gioco con SDL.NET
dic 4
Il tempo di pensare è finito… abbiamo un’idea vaga di quello che vogliamo fare, abbiamo pensato un po a qualche particolare. Nulla di sicuro però. Questo vuol dire che è tempo di mettere tutto per iscritto o perlomeno iniziare a capire l’importanza degli appunti!
Iniziamo, allora, a stilare un elenco di aspetti del nostro gioco.
- Il gioco parla di una moglie incazzata che lancia degli oggetti al marito. Il marito deve raccoglierli e questo permette di guadagnare 10 punti per ogni oggetto raccolto.
- Gli oggetti che cadono seguono il percorso di una griglia 3×3. Nel disegno a seguire è spiegato tutto meglio.

Come potete vedere in quest’immagine, l’area in cui gli oggetti cadranno sarà la sopracitata griglia 3×3. Dove leggete il testo “finestra 1″, “finestra 2″, “finestra 3″ c’è l’indicazione per la finestra rispettiva.
La moglie infatti getterà, ogni secondo, un oggetto da una a caso di queste finestre. Il giocatore starà invece sotto la griglia, dove dovrà prenderla. Da questo sappiamo per certo che:
- La moglie potrà assumere tre posizioni (finestra 1, 2 o 3)
- Il giocatore potrà spostarsi in tre posizioni (sotto la finestra 1, 2 o 3)
E’ scontato ma lo dico per maggiore comprensione: l’oggetto fulmine si trova sotto la finestra tre, in prima posizione (partiremo dall’alto). Per comodità diremo (3,1). La forbice si trova in (2,2).
Ma torniamo ai nostri punti.
- Gli oggetti cadranno ad intervalli regolari, la cui durata però inizierà pian piano a diminuire. In questo modo si può aumentare la difficoltà del gioco con il raggiungimento di un numero maggiore di punti. Questo evita anche che il gioco sia tremendamente piatto.
Nello specifico, gli oggetti inizieranno a cadere con un intervallo di un secondo. Ogni secondo la moglie si affaccerà da una delle tre finestre e lancerà l’oggetto. Come si può fare ad aumentare la velocità degli oggetti in caduta?
Io ho usato il seguente metodo, che penso possa essere sicuramente affinato.
Innanzitutto, si deve pensare che il gioco ha un’ammontare di Frames per Secondo. Do per scontato che sappiate cosa sono, per cui vi dico subito che è possibile gestire questo aspetto tramite la variabile Events.Fps. Per cui, per prima cosa, le assegneremo il valore 60.
Successivamente, useremo due altre variabili:
- frames
- framelimit
“frames” verrà usato come contatore del frame attuale in cui ci si trova, mentre “framelimit” sarà il limite dell’intervallo di cui ho parlato sopra.
Ora facciamo un esempio pratico, non scriverò codice ma comunque in un modo comprensibile.
- “frames” è inizialmente settata a 0;
- “framelimit” è inizialmente settata a 60;
- Se frames < framelimit
- frames = frames + 1;
- altrimenti
- (qui viene creato un nuovo oggetto da far cadere e viene scelta una nuova posizione per la moglie);
- frames = 0;
Dopodichè controlliamo il punteggio: ogni volta che avanzeremo di 300 punti (quindi 300, 600, 900 e così via) diminuiremo di un tot il framelimit (nel mio esempio è 5). Quindi, a 300 punti avremo un framelimit di 55, a 600 di 50 e così via.
Spero di essere stato chiaro. Torniamo ai punti:
- Il giocatore non giocherà in eterno, ma avrà 3 vite. Una vita viene persa quando non riesce a prendere un oggetto e quando le vite saranno pari a 0 il gioco terminerà.
- All’inizio, inoltre, mostreremo una piccola schermata che precederà il gioco vero e proprio, illustrando la trama e gli obiettivi.
Ciò ci porta a spendere due parole sulle varie situazioni di gioco. Appena avvieremo il gioco, infatti, non avremo subito a che fare con la moglie incazzata. Ci verrà mostrata la schermata delle istruzioni finchè non premeremo Invio. Dopodichè verremo portati nella scena di gioco: adesso dovremo premere ancora invio per iniziare e solo allora giocheremo veramente. Una sorta di schermata in cui si dice “press start to play”… dovreste averla presente ![]()
Per questo motivo ho suddiviso in “stati” le varie situazioni di gioco. Inoltre, ho voluto identificare in modo distinto gli stati del gioco e gli stati della partita (dato che possiamo avere più partite prima che l’utente si scocci ed esca):
Stati del Gioco:
- Schermata Iniziale
- Schermata di Gioco
- Uscita dal Gioco
Stati della Partita:
- Prima
- Durante
- Fine
Passeremo da uno stato all’altro seguendo delle condizioni ben determinate. Eccole qui di seguito.
- Schermata Iniziale:
- Premendo Invio andremo in “Schermata di Gioco”
- Premendo Esc andremo in “Uscita dal Gioco”
- Schermata di Gioco: (qui iniziamo a gestire i vari stati della partita)
- Stati della Partita:
Prima:
- Premendo Esc andremo in “Uscita dal Gioco”
- Premendo Invio andremo in “Durante”
Durante:
- Premendo le Frecce Direzionali muoviamo il personaggio
- Premendo Esc andremo in “Prima”
- Finendo le vite del personaggio andremo in “Fine”
Fine:
- Premendo Esc andremo in “Uscita dal Gioco”
- Premendo Invio andremo in “Prima”
Tranne per quello che riguarda lo stato “Durante” della Partita, potete vedere che tutti i passaggi di stato sono causati dall’input dell’utente.
Ora che abbiamo tutto pronto e chiaro in mente, possiamo iniziare a guardare il lato del codice vero e proprio… è tempo di sedersi al pc!



Ultimi Commenti