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!

  • Share/Bookmark