lunedì 9 marzo 2009

4) Xna Videogame Tutorial : Il primo sprite

Ooooh!!! Finalmente inizio a farvi vedere qualcosa di concreto! Avete presente un videogame FPS 3d con grafica generata proceduralmente, HLSL di ultima generazione che Directx 11 a confronto fa ridere, con esplosioni ed illuminazioni da panico?..... ecco benissimo! non faremo niente di tutto questo :D vi mostrerò semplicemente cosa dovrete fare per visualizzare la vostra piccola e piatta astronave 2d sul vostro monitor! ... lo so come inizio non è molto, eppure vedrete che vi darà soddisfazione.... da qualche parte bisogna pur partire!!









Dato che il tutorial vero e proprio inizierà qualche riga sotto vi consiglierei prima di tutto di chiedervi quale sia il vostro livello. Io parlerò di XNA in modo molto semplice, e gli argomenti di questi primi tutorial non saranno certamente complessi... ma.... se non avete una buona infarinatura di programmazione ad oggetti inizierei leggendo prima qualche guida o meglio ancora studiando un libro in modo approfondito.
Questo per esempio è gratuito ... http://www.mindview.net/Books/TICPP/ThinkingInCPP2e.html tratta c++ ma vi assicuro che come conoscenza acquisibile va più che bene!

Vi consiglio di studiare prima le basi perchè altrimenti questi semplici tutorial si trasformeranno in un inferno senza senso e a quel punto vi demoralizzerete mollando subito il colpo.
Scusate per questa triste premessa ma è da anni che desideravo scriverne una.

Premesse demoralizzanti a parte .... su! mouse e tastiera e cominciamo!

Iniziamo:
Come vi ho anticipato nel post scorso, nei prossimi giorni svilupperemo un semplice videogame. Non avremo molte pretese se non quella di imparare alcuni concetti fondamentali legati alle basi di XNA!

Quello con cui avremo a che fare oggi è la stampa di un'immagine 2d (la nostra astronave) che si muoverà da destra sinistra nella finestra di gioco.

Installazione:

Per chi di voi non avesse già installato XNA 3.0 e Visual C#2008:


Installer Visual C# 2008 A destra dovreste vedere un box simile a questo. Dopo aver scelto la vostra lingua preferita cliccate su download e scaricate l'.exe, quindi seguite la procedura di download e installazione.






Installer Game studio XNA 3.0 , anche in questo caso cliccate sul pulsante download scaricate e seguite le istruzioni.






Creare il progetto:
Una volta installati entrambi i sw, lanciate Visual C# 2008 e create un nuovo progetto di tipo windows game (3.0). Vi metto un'immagine sgranata e illeggibile per aiutarvi a capire il passaggio :P, lo so è semplice.... non vi ho preso per rimbambiti! ma almeno così siete sicuri no? (io la prima volta non trovavo "windows game (3.0)" perchè non cliccavo sulla voce xna project, sotto a project types nella barra di sinistra .....



Chiamate il progetto come meglio credete e posizionatelo nel vostro Hd nella cartella parent dello spazio dove archiviate i film hard, in questo modo la troverete subito quando dovrete riaprire il progetto tra qualche giorno!

Ok...a questo punto troverete davanti a voi una finestra di visual c suddivisa in vari ambiti, purtroppo non ho moltissimo tempo per spiegarvi al meglio come sono disposti i contenuti nella finestra di Visual C, l'importante è notare che a destra avete una visualizzazione dei file e degli elementi che compongono il progetto, a sinistra il vostro codice e in basso un frame per messaggi d'errore (warnings.. etc).

I primi file:
Analiziamo molto velocemente i file presenti nella barra destra, cliccando su properties, e sul suo figlio AssemblyInfo.cs troverete un file di "configurazione" che sinceramente non mi è mai capitato di modificare.

Program.cs è il punto d'ingresso del programma che creeremo, come potete notare qui si trova il metodo main, che chiama la funzione run dell'oggetto game di tipo Game1.
Il file Game1.cs è il file centrale del nostro programma, dove andremo a definire l'oggetto che viene richiamato da Program.cs e sarà il cuore del nostro videogame.
Aprendo questo file troverete alcune funzioni (che sono quelle che vi ho anticipato qualche articolo fa ).

Carichiamo l'immagine:
Il nostro scopo per oggi è quello di far muovere uno sprite nella nostra finestra di gioco, quindi prima di tutto dovremmo avere qualcosa da far muovere!

Scaricate questa immagine che sarà la nostra bellissima astronave!
(una nota su questa grafica. Purtroppo non riesco più a trovare la fonte dalla quale l'ho reperita, trattasi di un forum che penso sia stato cancellato... questo vale anche per le prossime immagini... se qualcuno di voi incontrasse in rete quest'immagine me lo faccia notare.. così linkero l'autore! grazie mille).

Ora, il primo passaggio per inserire l'immagine tra i file dei quali potremmo disporre, è semplicemente cliccare con il tasto destro sulla voce "Content" nel frame dei contenuti a destra
e dunque "Add" e "Existing Item". A questo punto inseriremo l'immagine della nostra astronave (spaceship.png)




Questo che per voi è stato un semplice passaggio di 3 click, in realtà racchiude un sistema di import e gestione dei contenuti mooooooolto interessante, trattasi della cosidetta Content pipeline di XNA.
Tramite questa comodissima features voi non dovrete assoultamente preoccuparvi di trovare un modello di importazione per i vostri contenuti, dato che questo lavoro lo farà XNA per voi...non vi parlo solo di jpg png etc... ma parliamo di file 3d come .X ( + altri formati) e audio (previa lavorazione con xact.. che vedremo più avanti) . Una cosa interessante di questa modalità è che comunque sarete liberi di scrivere un vostro importer(o di terze parti) o di estendendere la content pipeline standard.


Il primo codice:
A questo punto è il caso di iniziare a scrivere qualcosa ... dato che per ora ha fatto tutto xna per noi.
Vi ricordo che vogliamo stampare uno sprite della nostra astronave che si muova da destra a sinistra nella finestra di gioco.

Gli elementi che entrano in gioco sono quindi:

1) la grafica della nostra astronave
2) la posizione dell'astronave
3) la velocità dell'astronave
4) lo spazio entro il quale si potrà muovere (la finestra di gioco)

Se date una ripassata alla lista delle funzioni che vi ho presentato qualche giorno fa (la trovate qui
http://imparandoxna.blogspot.com/2009/02/cose-xna-e-come-funziona.html )
noterete che ogni funzione ha degli scopi ben precisi, ora vi riassumerò in breve come utilizzeremo queste funzioni e sotto riporterò i vari codici:

La funzione Initialize si occuperà di inizializzare la posizione di partenza dell'astronave, che vogliamo sia più o meno al centro della finestra.
La funzione LoadContent caricherà la texture della nostra astronave. Attraverso la funzione Update faremo variare il suo parametro posizione e nella Draw stamperemo l'astronave secondo il parametro calcolato nella update.

Prima di tutto settiamo delle variabili di classe, prima della funzione Game1().

VARIABILI DI CLASSE e COSTRUTTORE

//Impostazioni astronave-------------------------------------
Texture2D tex_ship;//Texture atronave
Vector2 pos_ship = Vector2.Zero;//coordinate posizionali
float spd_ship = 3.0f;//Velocità

public
Game1()
{

graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";

}

Il tipo Texture2d come potete immaginare serve per storicizzare informazioni di tipo immagine, mentre la vector2 rappresente un vettore a due chiavi (X,Y) e ha alcune funzionalità per facilitare la vita del programmatore come Vector2.Zero che setta automaticamente sia X che Y a 0.
L'oggetto GraphicsDeviceManager(this) è il riferimento alla nostra GPU, mentre la Content.RootDirecotory definisce il nome della cartella nella quale posizioneremo i contenuti da caricare tramite la ContentPipeline.


INITIALIZE

protected
override void Initialize()
{

//Coordinate iniziali
float x_pos = (Window.ClientBounds.Width / 2);
float
y_pos = (Window.ClientBounds.Height / 2);
pos_ship = new Vector2(x_pos, y_pos);

base.Initialize();
}
Dunque nella initialize setteremo la posizione iniziale dell'astronave, prendendo la dimensione della nostra finestra
Window.ClientBounds.Width - Height e dividendo per due, quindi associeremo le posizioni calcolate alla posizione dell'astronave pos_ship.


LOAD CONTENT

protected override void LoadContent()
{

spriteBatch = new SpriteBatch(GraphicsDevice);
tex_ship = Content.Load<Texture2D>(@"spaceship");
}

Nella LoadContent caricheremo la texture dell'astronave, non vi ho fatto notare prima che se cliccate sull'immagine caricate nell'area dei contenuti a destra e vi spostate a fondo pagina sotto la voce properties, vedrete le impostazioni legate all'immagine e insieme a queste il nome con il quale dovrete richiamare l'immagine nel vostro programma (in questo caso spaceship). Come noterete non vi preoccupate più dell'estensione del file immagine.
Infatti guardate come istanziamo l'oggetto Texture2d :
Content.Load(@"spaceship");
Utilizziamo la funzione Load dell'oggetto content, facendo riferimento direttamente al nome che la contentpipeline ha associato per noi all'immagine caricata. (se avessimo inserito l'immagine nella cartella images avremo naturalmente dovuto riportare l'intero persorso "images/spaceship").
Per quanto riguarda lo spriteBatch si tratta dell'oggetto attraverso il quale stamperemo gli sprites.


UPDATE
protected override void Update(GameTime gameTime)
{

// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this
.Exit();

pos_ship.X += spd_ship;

if
(
(
pos_ship.X > Window.ClientBounds.Width - tex_ship.Width)
||

pos_ship.X < 0)
{

spd_ship *= -1;
}


base.Update(gameTime);
}

Finalmente entriamo nel loop, la funzione update a ogni ciclo modificherà la posizione X dell'astronave, quando l'astronave arriverà contro la parete di sinistra
(pos_ship.X > Window.ClientBounds.Width - tex_ship.Width) invertirà la sua rotta (spd_ship *= -1;)....quando incontrerà la parete di destra (pos_ship.X < style="font-style: italic;"> (spd_ship *= -1;)
Per ora tralasciate la riga dove viene intercettato l'input da Pad (if (GamePad.GetState... etcc) ne parleremo più avanti.

DRAW
protected override void Draw(GameTime gameTime)
{

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();
spriteBatch.Draw(tex_ship, pos_ship, Color.White);
spriteBatch.End();

base.Draw(gameTime);
}

E infine disegnamo l'astronave nella posizione definita nell'update
Ci cureremo di inserire la funzione SpriteBatch.Draw tra i metodi Begin() e End() dopo aver "pulito" la schermata (con la funzione Clear) da quanto stampato nel ciclo precedente, se non ci curassimo di cancellare le info stampate nel ciclo precedente vedremmo la nostra astronava ripetuta tante volte quante volte si è entrati nel ciclo update-draw.
La funzione Draw dell'oggetto spriteBatch ha diversi prototipi che accettano diversi parametri , per ora tenete solo in testa che lo spritebatch è come la vostra lavagna, e che attraverso il metodo draw, sopra utilizzato, andate a definire
1) quale immagine stampare (tex_ship)
2) in che posizione (pos_ship)
3) eventualmente una tinta, .White è neutro.

Tramite lo spritebatch potete gestire anche ordini di stampa trasparenze e modalità di visualizzazione, dando dei parametri alla funzione Begin() .


Fine
A questo punto cliccando su f5 se avete seguito quello che ho scritto qui sopra, dovreste vedere la nostra astronave muoversi da destra a sinistra e rimbalzare nello schermo come una pallina!


Bravi! Per oggi basta così perchè sono veramente fuso.... pensavo di non aver niente da dire su questo argomento e invece mi sembra di essermi dilungato fin troppo, spero di non avervi addirittura annoiato.

Con le prossime cercherò di essere più rapido!!

Download Sorgenti:
1.sprite2d.zip

Ciao a tutti










8 commenti:

Anonimo ha detto...

Ottimo! W XNA :)

Yari ( ImparandoXNA ) ha detto...

wow! Wilez! che figata vedere che passi di qui :P

Anonimo ha detto...

perfetto, già così si comincia a capirne il funzionamento...faccio notare che c'è un piccolo errore di sintassi nel paragrafo prima di "DRAW" probabilmente si è incasinato il codice c# con quello della pagina^^

Yari ( ImparandoXNA ) ha detto...

argh probabilmente si... uso un convertitore per produrre l'html che contiente il codice... probabilmente si è impastato qualcosa.. cerco di correggere l'errore... usate sempre il codice allegato per essere sicuri

Arema ha detto...

Ho trovato questo blog e lo sto seguendo con molta soddisfazione. Grazie 1000 per l'ottimo lavoro svolto. Spero di capire fino in fondo il tutorial...

Anonimo ha detto...

noooooooooo....mi da sempre errori...sto impazzendo...

Anonimo ha detto...

errore di scheda grafica ?!? .. mi sembra strano, il portatile è praticamente nuovo !!

Anonimo ha detto...

Devi disabilitare gli effetti HD.
Vai su progetto-> proprietà->game profile.

Cambia HiDef in Reach

Posta un commento