Archive for 18 novembre 2009
Output – Fonts – Guida SDL.NET
nov 18
Come potrete facilmente immaginare, le immagini non sono l’unica componente grafica di un gioco. Molto spesso, infatti, anche nel gioco più semplice dobbiamo fare uso dei font: si pensi alla creazione delle GUI, delle varie interfacce o anche al punteggio del più semplicistico clone di pong.
Insomma, per poter fare qualcosa di decente abbiamo bisogno di uno strumento versatile che ci consenta di gestire i fonts e l’output testuale senza troppi problemi. In nostro aiuto, per quanto riguarda l’SDL.NET, arriva la classe Font. E sarà proprio nelle prossime righe che cercheremo di analizzare, almeno nelle sue basi, questo utile strumento.
Per prima cosa vediamo come iniziare ad usare un oggetto di questo tipo.
Font f1 = new Font(“font1.ttf”, 14);
f1 è un oggetto di tipo Font. Nel nostro caso, al costruttore passiamo una stringa con il nome del font utilizzato ed un intero che indica la grandezza del testo. Nulla di più semplice ed intuitivo. Dopo questa dichiarazione, in memoria abbiamo già il nostro font pronto ad essere utilizzato.
Adesso però dobbiamo scrivere qualcosa: ecco, qui di seguito, il codice che ci serve.
Surface testo = f1.Render(“testo da scrivere!”, System.Drawing.Color.Black);
Surface testo = f1.Render(“testo da scrivere!”, System.Drawing.Color.Black, System.Drawing.Color.White);
Volendo spiegare in parole povere il funzionamento del meccanismo, pensate alla surface testo come un “foglio”, e all’oggetto f1 come una “stampante”. Nella prima riga di codice che ho riportato stiamo dicendo ad f1 di “stampare” sulla Surface “testo” la stringa “testo da scrivere!”, in colore nero. La surface, successivamente, sarà pronta per essere utilizzata. Il metodo Render ha svariati overload, tra cui l’altro che ho riportato: oltre al testo e il colore, nel metodo passiamo come terzo argomento anche il colore di sfondo da utilizzare.
La personalizzazione del testo, tuttavia, non finisce qui: la classe Font mette a disposizione svariate proprietà di customizzazione e formattazione, per fornire la massima flessibilità. Di seguito qualche esempio.
- Proprietà Bold: permette di decidere se il testo da renderizzare sarà in grassetto oppure no. Di default, questa proprietà è settata su False.
- Proprietà Italic: in questo caso possiamo decidere se il nostro testo sarà in corsivo oppure no. La proprietà è impostata su False di default.
- Proprietà Underline: Impostata su False normalmente, questa proprietà consente di decidere se il testo da renderizzare sarà sottolineato.
Oltre a queste proprietà c’è un’altra che riassume tutte e tre contemporaneamente, che si chiama Style. I valori che può assumere sono compresi nell’enumerazione SdlDotNet.Graphics.Styles. Ecco un esempio pratico qui di seguito.
f1.Style = Styles.Underline;
Insomma, la gestione del testo, almeno a livello base,è veramente molto semplice e facile da capire. Ovviamente, le cose si possono complicare se ci sono necessità riguardanti, per esempio, testi multilinea: a tutto però c’è una soluzione. Ma per adesso rimarremo sul semplice.
Come avete potuto notare dagli esempi (e se non l’avete notato ci penso io
) i colori usati nei testi e negli sfondi sono quelli compresi nella struct System.Drawing.Colors. In questo modo avremo già pronti un sacco di colori.
Ma cosa fare se abbiamo necessità di utilizzare un colore di cui conosciamo perfettamente i valori RGB? Non c’è problema, ecco la sintassi!
f1.Render(“testo da scrivere!”, System.Drawing.Color.FromArgb(0, 0, 0));
La struttura Color infatti presenta il metodo FromArgb, dove rgb sta per Red, Green e Blue. Un attimo.. ma la A? FromArgb presenta anche due overload, ed uno sguardo veloce all’intellisense permette di capire subito di cosa si tratta: parliamo di Alpha, ed il valore che può assumere va da 0 a 255.
Un’altro overload di FromArgb consente invece di fornire come parametro un int a 32 bit nel quale specificare il numero ARGB che rappresenta il nostro colore. Come potete vedere c’è l’imbarazzo della scelta anche in questo caso.
Prima di concludere questa parte, dovete sapere che esiste anche un altro strumento per gestire i testi: parlo di TextSprite, contenuto in SdlDotNet.Graphics.Sprites. Stavolta, però, ci si ferma alla gestione base dei fonts e riprenderemo il discorso successivamente.
Adesso, infatti, lasciamo perdere per un po’ il mondo della vista, per addentrarci in quello dell’udito
Nel prossimo articolo parleremo di Audio per i nostri programmi.
Output – Immagini – Guida SDL.NET
nov 18
E’ tempo di mostrare qualcosa sullo schermo, vero? Sono d’accordo con voi, iniziamo a parlare delle Surface, i primi oggetti che ci accompagneranno nella rappresentazione su schermo dei nostri file grafici. Volendo tradurre alla lettera dalla Wiki ufficiale, possiamo ottenere la spiegazione più esatta per questa classe:
“Le Surface in SDL.NET rappresentano, genericamente, delle informazioni grafiche. E’ possibile crearle da zero (e quindi disegnarci ciò che si vuole) oppure caricando dei files dal disco fisso o da un array di bytes. Ogni Surface ha una propria larghezza ed altezza e possiedono delle funzionalità di disegno sulla superficie stessa.”
Le cose non sono ancora chiare? Tranquilli, ecco un bel programma di prova, che verrà prontamente spiegato.
[code]]czoxMDg3OlwiDQp1c2luZyBTeXN0ZW07DQoNCnVzaW5nIFNkbERvdE5ldC5Db3JlOw0KdXNpbmcgU2RsRG90TmV0LkdyYXBoaWNzOw17WyYqJl19Cg0KbmFtZXNwYWNlIERlbW8NCnsNCiAgICBwdWJsaWMgY2xhc3MgR2FtZQ0KICAgIHsNCiAgICAgICAgU3VyZmFjZSBzY2hlcm1hdHtbJiomXX1hID0gVmlkZW8uU2V0VmlkZW9Nb2RlKDgwMCwgNjAwKTsNCiAgICAgICAgU3VyZmFjZSBpbW1hZ2luZSA9IG5ldyBTdXJmYWNlKFwiaXtbJiomXX1tbWFnaW5lLmpwZ1wiKTsNCg0KICAgICAgICBbU1RBVGhyZWFkXQ0KICAgICAgICBwdWJsaWMgc3RhdGljIHZvaWQgTWFpbigpDQogIHtbJiomXX0gICAgICB7DQogICAgICAgICAgICBHYW1lIGFwcCA9IG5ldyBHYW1lKCk7DQogICAgICAgICAgICBhcHAuR28oKTsNCiAgICAgICAge1smKiZdfX0NCg0KICAgICAgICBwdWJsaWMgR2FtZSgpDQogICAgICAgIHsNCiAgICAgICAgICAgIEV2ZW50cy5GcHMgPSA2MDsNCiAgICAgICB7WyYqJl19ICAgICBWaWRlby5XaW5kb3dDYXB0aW9uID0gXCJHZXN0aW9uZSBTdXJmYWNlIC0gU0RMLk5FVFwiOw0KICAgICAgICB9DQoNCiAgICAge1smKiZdfSAgIHB1YmxpYyB2b2lkIEdvKCkNCiAgICAgICAgew0KICAgICAgICAgICAgRXZlbnRzLlF1aXQgKz0gbmV3IEV2ZW50SGFuZGxlcjx7WyYqJl19UXVpdEV2ZW50QXJncz4odGhpcy5RdWl0KTsNCiAgICAgICAgICAgIEV2ZW50cy5UaWNrICs9IG5ldyBFdmVudEhhbmRsZXI8VGlja3tbJiomXX1FdmVudEFyZ3M+KEV2ZW50c19UaWNrKTsNCiAgICAgICAgICAgIEV2ZW50cy5SdW4oKTsNCiAgICAgICAgfQ0KDQogICAgICAgIHZve1smKiZdfWlkIEV2ZW50c19UaWNrKG9iamVjdCBzZW5kZXIsIFRpY2tFdmVudEFyZ3MgZSkNCiAgICAgICAgew0KICAgICAgICAgICAgc2NoZXJ7WyYqJl19bWF0YS5GaWxsKFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKTsNCg0KICAgICAgICAgICAgc2NoZXJtYXRhLkJsaXQoaW1tYWdpbntbJiomXX1lKTsNCg0KICAgICAgICAgICAgc2NoZXJtYXRhLlVwZGF0ZSgpOw0KICAgICAgICB9DQoNCiAgICAgICAgcHJpdmF0ZSB2b2lkIFF1e1smKiZdfWl0KG9iamVjdCBzZW5kZXIsIFF1aXRFdmVudEFyZ3MgZSkNCiAgICAgICAgew0KICAgICAgICAgICAgRXZlbnRzLlF1aXRBcHBsaWN7WyYqJl19YXRpb24oKTsNCiAgICAgICAgfQ0KICAgIH0NCn0NClwiO3tbJiomXX0=[[/code]
Partiamo dalle prime righe:
using System;
using SdlDotNet.Core;
using SdlDotNet.Graphics;
Qua dovremmo esserci: includiamo i namespace che ci servono per i nostri scopi, attraverso la direttiva using.
Surface schermata = Video.SetVideoMode(800, 600);
Ecco la prima delle nostre Surface. Come detto precedentemente, queste possono essere create in vari modi: l'oggetto “schermata” che stiamo dichiarando è speciale: rappresenta infatti la finestra di gioco che noi utilizzeremo.
Il tutto viene reso possibile grazie al metodo SetVideoMode della classe Video, che restituisce appunto una Surface. In questo modo abbiamo deciso che la nostra finestra avrà una dimensione di 800 pixel per 600 pixel.
Ora abbiamo:
Surface immagine = new Surface("immagine.jpg");
Questa surface invece viene creata passando come argomento del metodo costruttore il nome del file da caricare. In questo caso caricheremo il file “immagine.jpg”, situato nella stessa cartella del nostro file exe compilato. Una volta che il nostro oggetto viene creato è pronto per essere mostrato. Continuiamo però con il codice:
public Game()
{
Events.Fps = 60;
Video.WindowCaption = "Gestione Surface - SDL.NET";
}
Qui abbiamo il metodo costruttore della nostra classe Game, che svolge essenzialmente due operazioni: imposta il limite dei frame per secondo a 60 utilizzando la proprietà Fps della classe Events e cambia il titolo alla finestra del programma, stavolta utilizzando WindowCaption di Video. Molto semplice come concetto. Adesso:
public void Go()
{
Events.Quit += new EventHandler<QuitEventArgs>(this.Quit);
Events.Tick += new EventHandler<TickEventArgs>(Events_Tick);
Events.Run();
}
Il metodo Go aggiunge gli Handler per gli eventi che vogliamo gestire: in questo caso ne abbiamo due: Quit, già visto in precedenza, e Tick. Tick permette di gestire ciò che succede ad ogni frame, risultando particolarmente utile nell'aggiornamento dei valori delle variabili in gioco. Stando al limite dato precedentemente, la nostra funzione Events_Tick viene eseguita 60 volte al secondo. Quello che facciamo nel metodo Events_Tick è spiegato nelle righe successive:
void Events_Tick(object sender, TickEventArgs e)
{
schermata.Fill(System.Drawing.Color.Black);
schermata.Blit(immagine);
schermata.Update();
}
Ed ecco l'utilizzo effettivo delle nostre Surface! Come si può vedere, in questo metodo eseguiamo tre operazioni:
- Tramite la funzione Fill riempiamo tutta la schermata di nero. Può apparire insensato, ma pensate ad un file immagine con delle trasparenze (per esempio un file PNG) che si sposta nel tempo. Senza riempire lo schermo di nero tutte le volte avremmo un effetto fastidioso dovuto alla “non pulizia” della surface, se così la vogliamo chiamare.
- Tramite il metodo Blit invece disegnamo la nostra immagine. Blit è un metodo che ha ben 8 overload: ciò vuol dire che ci sono ben 9 modalità diverse con cui disegnare sulle surface. Nel nostro caso abbiamo passato solo il nome della Surface da disegnare: questo vuol dire che le coordinate in cui verrà disegnata la nostra Surface saranno (0,0) rispetto alla “schermata”.
- Il metodo Update si occupa infine di “aggiornare” il nostro frame e fare in modo che tutte le eventuali modifiche del sistema siano mostrate a schermo. Non dimenticatelo alla fine della fase di disegno, è importante!
Ma torniamo al punto 2: perchè queste coordinate sono (0,0)? E' semplice da spiegare: la Surface “schermata” rappresenta la finestra stessa del programma. Di conseguenza, il punto situato più in alto a sinistra avrà delle coordinate pari a 0 sull'asse x ed altrettanto sulla y.
Per disegnare la nostra immagine in una posizione differente, la sintassi sarà la seguente:
schermata.Blit(immagine, new System.Drawing.Point(20, 20));
Stavolta disegneremo la nostra immagine alle coordinate (20,20), e non più (0,0), sui nostri assi cartesiani. A tal proposito devo ricordarvi una cosa molto importante: gli assi cartesiani sullo schermo del pc sono ribaltati sull'asse Y. In poche parole, ecco due immagini per chiarire le idee.


Ciò che abbiamo dopo il metodo Events_Tick è il codice del metodo Quit, che ci consente di uscire dal programma.
Tornando a parlare genericamente, l'oggetto Surface supporta una buona quantità di formati grafici:
- BMP
- PNM
- XPM
- LBM
- PCX
- GIF
- JPEG
- PNG
- TGA
Trasparenza
Ovviamente non è solo questo quello che dobbiamo dire riguardo alle Surface e al loro utilizzo. Un'altra feature molto utile è quella della gestione della trasparenza, che avviene tramite due proprietà:
- TransparentColor
- Transparent
Facciamo un esempio. Abbiamo un'immagine in un file PNG che vogliamo utilizzare come cursore del mouse nel nostro gioco. Caricandola e mostrandola sullo schermo tramite la procedura sopra mostrata, tuttavia, non avremmo il risultato desiderato: oltre a mostrare il cursore, infatti, verrebbe mostrato anche il quadrato in cui è contenuta l'immagine, ovvero tutto il file immagine, per intero. Come facciamo ad evitare questo problema?
Per prima cosa, dobbiamo specificare il colore di trasparenza del nostro file. Ecco un veloce esempio, usando sempre la nostra surface “immagine”:
immagine.TransparentColor = System.Drawing.Color.White;
In questo modo diciamo al sistema che, quando mostrerà a schermo la surface “immagine” dovrà ignorare tutti i pixel di colore bianco. Dopo questo, usiamo anche la proprietà Transparent, semplicemente impostandola su True. Ricordate che questo step è necessario.
immagine.Transparent = true;
Adesso il nostro cursore sarà bello e pronto da mostrare senza problemi
. Ovviamente queste istruzioni è bene non metterle nel loop senza condizioni: io per esempio le metto nel metodo costruttore della mia classe. Ecco un esempio completo, per mostrare dove ho posizionato le istruzioni.
public Game()
{
immagine.TransparentColor = System.Drawing.Color.White;
immagine.Transparent = true;
Events.Fps = 60;
Video.WindowCaption = "Gestione Surface - SDL.NET";
}
Alpha Blending
Anche l'Alpha Blending è decisamente semplice da utilizzare. Come per la trasparenza, dovremo scrivere solamente due righe di codice, utilizzando due proprietà:
- Alpha
- AlphaBlending
Alpha è di tipo byte e va da 0 a 255. Impostandolo su 0 avremo la totale trasparenza della surface. A 255 invece la surface sarà totalmente visibile. Dopo aver impostato l'Alpha procediamo quindi ad attivare l'AlphaBlending impostando la proprietà su true, proprio come per la trasparenza. Se non effettuiamo quest'ultimo passo la proprietà Alpha verrà ignorata.
Ecco un esempio:
immagine.Alpha = Convert.ToByte(255);
immagine.Alpha = Convert.ToByte(0);
immagine.AlphaBlending = true;
Come suggerisce anche la Wiki ufficiale, un uso saggio delle surface può essere anche l'uso delle SurfaceCollections, ovvero strutture dinamiche che permettono di gestire altrettanto dinamicamente questo tipo di oggetto. Tuttavia ne parleremo più in la, magari quando riuscirò a scrivere una sorta di sezione “avanzata” di questa guida. Per ora, per quanto riguarda le surface, è tutto!



Ultimi Commenti