Posts tagged disegno

Disegnare il testo su schermo – Grafica – XNA Tutorials

In questo articolo analizzeremo DrawString, il metodo della classe SpriteBatch che si occupa di disegnare a schermo il testo. Vedremo velocemente come caricare e un font in memoria e successivamente smanetteremo un pò, guardando i vari risultati ottenuti.

Innanzitutto, lavorando con XNA dobbiamo sapere che il font viene rappresentato, come risorsa, tramite un file di tipo SpriteFont. Questo file conterrà la descrizione del font che utilizzeremo: parametri come la grandezza, il nome del font e così via saranno specificati qui.

Per creare un file SpriteFont, clicchiamo con il pulsante destro del mouse su Content, nell’Esplora Soluzioni, quindi su Aggiungi -> Nuovo Elemento. (in figura il procedimento)

Senza titolo-2

Ci si aprirà una finestra dove dovremo selezionare il tipo di risorsa da creare e il nome da assegnare. Ovviamente sceglieremo SpriteFont e daremo come nome, per esempio, “font1″.

Senza titolo-4

(click per ingrandire)

Dando l’ok sarà questo il codice che ci ritroveremo davanti per questa risorsa (ho cancellato i commenti per risparmiare spazio):

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">
    <FontName>Kootenay</FontName>

    <Size>14</Size>

    <Spacing>0</Spacing>

    <UseKerning>true</UseKerning>

    <Style>Regular</Style>

    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

I parametri sono veramente semplici da capire. FontName definisce il nome del font utilizzato: lo cambierò in “Arial” (senza virgolette ovviamente). Size indica la grandezza del font da utilizzare in fase di scrittura. Spacing indica invece la larghezza tra un carattere e l’altro, mentre UseKerning è un opzione che gestisce il layout del font. Style consente inoltre di decidere che tipo di stile applicare al testo scritto: grassetto, corsivo e così via.

La CharacterRegion indica l’insieme dei caratteri che è possibile riprodurre. Per ora lo lasceremo così, successivamente modificheremo questi valori per permetterci di riprodurre altri caratteri.

Ecco quindi come appare il file dopo la mia piccola modifica:

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">
    <FontName>Arial</FontName>

    <Size>14</Size>

    <Spacing>0</Spacing>

    <UseKerning>true</UseKerning>

    <Style>Regular</Style>

    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

Ora che la nostra risorsa è pronta, dobbiamo includerla con il codice. Creiamo una variabile di tipo SpriteFont e, successivamente, carichiamo la nostra risorsa un pò come avevamo fatto con le immagini, nel metodo LoadContent.

Quindi, prima dichiariamo

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        SpriteFont font1;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

e dopo carichiamo.

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            font1 = Content.Load<SpriteFont>("font1");
        }

A questo punto non dobbiamo fare altro che disegnare un pò di cose a schermo. Iniziamo con una scritta semplice, la classica “Ciao Mondo!” (non poteva mancare). Modificando il codice del metodo Draw con le istruzioni riportate qui,

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();
            spriteBatch.DrawString(font1, "Ciao Mondo!!!", new Vector2(10, 10), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }

il risultato sarà semplicemente questo illustrato.

Senza titolo-6

(click per ingrandire)

Proviamo qualcos’altro.

Tornando ad analizzare il metodo SpriteBatch.DrawString, vediamo un pò quali sono i parametri che diamo.

  1. Il primo parametro di tipo SpriteFont è il font con cui disegneremo il testo. Verdana, Arial, Times New Roman di qualsiasi grandezza, questo è il punto di riferimento per eventuali cambiamenti.
  2. Il secondo parametro è la stringa di testo che vogliamo portare su schermo.
  3. Il terzo parametro è un vettore di tipo Vector2 che si occupa di definire su schermo la posizione del testo. Nel mio caso volevo mettere il testo in posizione x = 10 ed y = 10 ed ho definito così il vettore di conseguenza.
  4. Il quarto parametro è il colore del testo, che possiamo cambiare a nostro piacimento. Qui di seguito qualche prova con i valori Green, Red e Lime.

Senza titol654

Senza titolo-3

Senza titolo-2

Dopo queste prove con il colore vediamo l’overload del metodo da noi usato, che al posto dei classici quattro parametri ne presenta di più, precisamente 9. Grazie a questo metodo potremo ruotare il nostro testo:

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();

            spriteBatch.DrawString(
                                    font1,
                                    "testo di prova 2",
                                    new Vector2(200, 200),
                                    Color.White,
                                    10,
                                    new Vector2(
                                        font1.MeasureString("testo di prova 2").X/2,
                                        font1.MeasureString("testo di prova 2").Y/2
                                        ),
                                    1.0f,
                                    SpriteEffects.None,
                                    1
                                    );

            spriteBatch.End();

            base.Draw(gameTime);
        }

I primi quattro parametri rimangono invariati: non abbiamo bisogno di descriverli un’altra volta. Ciò che cambia invece arriva dopo. Abbiamo quel “10″ che rappresenta l’angolo di rotazione che vogliamo usare. Ovviamente serve un centro di rotazione, ed a questo serve il successivo parametro, di tipo Vector2. E’ prevista anche la possibilità di gestire lo scaling del testo (il ridimensionamento) tramite un parametro di tipo Float. Infine abbiamo il tipo di effetto da dare al testo (provate voi stessi a smanettarci per vedere i risultati) ed infine la profondità del layout come ultimo parametro.

Ecco qui il risultato del codice, ed anche con il testo per ora abbiamo finito.

Senza titolo55

(click per ingrandire)

P.S: è importante sapere come regolarsi con le CharacterRegions del file XML della risorsa. Come ho detto precedentemente, questo parametro del font permette di decidere quali caratteri verranno ridisegnati. I valori che notiamo nel codice

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">
    <FontName>Arial</FontName>

    <Size>14</Size>

    <Spacing>0</Spacing>

    <UseKerning>true</UseKerning>

    <Style>Regular</Style>

    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>

tra i tag Start ed End sono i codici ASCII di partenza e di arrivo dell’insieme dei caratteri riproducibili. In poche parole, il sistema sarà in grado di disegnare su schermo i caratteri che hanno il codice ASCII che va da 32 a 126. Volendo portare a schermo dei caratteri come “ò” oppure “à” dovremo necessariamente modificare l’intervallo, in quando non include questi caratteri. Al posto di 126, nel tag End, usate 255 e non dovreste avere ulteriori problemi.

Cheers.

  • Share/Bookmark

Ruotare una Sprite – Grafica – XNA Tutorials

Dunque, ora vediamo un pò, dopo aver imparato a disegnare una sprite su schermo, come ruotarla e disegnare quindi questo effetto. Questo articolo sarà suddiviso in due parti: nella prima osserveremo da vicino il metodo che utilizzeremo. Successivamente, creeremo un metodo che richiamato ad ogni frame darà l’effetto di movimento nella rotazione.

  • Il Metodo

Ecco qui il metodo da noi utilizzato: lo riporto qui di seguito e successivamente spiegherò ogni parametro. Per provare l’esempio vi basterà copiare il codice qui di seguito (adattandolo con i nomi degli oggetti che voi avete deciso)  sull’esempio dell’articolo precedente, senza cambiare altro.

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            spriteBatch.Draw(
                immagine,
                new Rectangle(400,200,immagine.Width,immagine.Height),
                null,
                Color.White,
                40,
                new Vector2(immagine.Width/2,immagine.Height/2),
                SpriteEffects.None,
                0
                );

            spriteBatch.End();

            base.Draw(gameTime);
        }

Il primo parametro, la Texture2D immagine, è semplicemente la texture che abbiamo caricato precedentemente in memoria e che vogliamo utilizzare.

Il secondo parametro, invece, è un oggetto Rectangle nel quale specifico la posizione nella quale voglio disegnare la texture e le dimensioni di questa.

Il terzo parametro, che dovrebbe rappresentare un’altro rettangolo, è stavolta definito come null. Potrebbe non significare niente, ma questo metodo Draw consente di disegnare anche delle parti di texture. Più avanti magari vedremo come funziona meglio questo discorso.

Il quarto parametro è il classico colore visto anche precedentemente. Ho specificato il White come nell’esempio precedente.

Il quinto parametro è invece proprio ciò che serve a noi: l’angolo della rotazione che vogliamo ottenere. Stavolta ho messo quaranta come primo valore che mi è venuto in mente, per fare l’esempio.

Il sesto parametro è un vettore che serve a definire quale sarà il centro della rotazione. E’ importantissimo e, dato che noi vogliamo far ruotare l’oggetto intorno a se stesso, il punto che prenderemo in considerazione sarà il centro preciso, ovvero la metà della lunghezza e la metà dell’altezza.

Gli altri due parametri finali per ora non ci interessano molto, lasciamoli così.

Et voilà, ecco il risultato:

5466545462

(Click per Ingrandire)

La nostra sprite è stata ruotata e il risultato è visibile su schermo.

  • Il Movimento

Wow, ad essere ruotata la nostra immagine è effettivamente ruotata. Ma se vogliamo farla muovere? L’effetto di rotazione può avvenire in tanti modi. Vi farò vedere due possibili casi: in base ad un fattore fisso (ad ogni frame ruoteremo di un tot la nostra immagine) oppure in base all’input dell’utente.

Vediamo come ruotare l’immagine in base ad un fattore fisso. Per rendere le cose semplici, ho dichiarato una variabile che rappresenterà l’angolo di rotazione.

public class Game1 : Microsoft.Xna.Framework.Game
{
   GraphicsDeviceManager graphics;
   SpriteBatch spriteBatch;

   Texture2D immagine;

   //ecco la nostra variabile, impostata inizialmente a zero.
   float rot = 0f;

Una volta creata questa variabile, la andiamo ad inserire nel contesto. Per prima cosa dobbiamo contare che la rotazione può avvenire (dato che parliamo in gradi) da 0° a 360°. Per questo ho deciso di scrivere in questo modo il metodo Update:

        protected override void Update(GameTime gameTime)
        {
            if (rot != 360) rot += 0.1f; else rot = 0f;

            base.Update(gameTime);
        }

L’operazione è veramente semplice da capire: ad ogni frame aggiungo 0.1 al al valore della rotazione. Appena verrà raggiunto il valore 360, la variabile verrà reimpostata a zero, in modo tale che il ciclo rinizi nuovamente. A questo punto basterà modificare il parametro in input nel metodo Draw:

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            spriteBatch.Draw(
                immagine,
                new Rectangle(400,200,immagine.Width,immagine.Height),
                null,
                Color.White,
                rot,
                new Vector2(immagine.Width/2,immagine.Height/2),
                SpriteEffects.None,
                0
                );

            spriteBatch.End();

            base.Draw(gameTime);
        }

Testiamo tutto premendo F5. Vi renderete conto da soli del risultato. Potete inoltre modificare il centro di rotazione per vedere le differenze: provate per esempio a togliere il “diviso due” dai valori dati in input, e vedrete l’immagine ruotare intorno al punto in basso a destra ;)

Adesso invece scopriremo come ruotare un’immagine in base all’input dell’utente. Qui inserirò solo delle istruzioni basilari e facili da capire, in modo tale da non complicare le cose. Il nostro obiettivo è il seguente: alla pressione della freccia destra sulla tastiera, la nostra immagine ruoterà.

Lasciamo immutato il metodo Draw, concentriamoci solamente sull’Update. Come potrete facilmente intuire, quello che faremo sarà veramente semplice: aumenteremo il valore della variabile rot solo quando il tasto sarà premuto. Per fare questo cambieremo il metodo Update in:

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                if (rot != 360) rot += 0.1f; else rot = 0f;
            }

            base.Update(gameTime);
        }

In questo caso ho semplicemente controllato, con istruzioni tra l’altro comprensibili (IsKeyDown(Keys.Right), per esempio) la pressione del tasto da noi desiderato.

Provate il risultato, alla prossima! ;)

  • Share/Bookmark

Disegnamo gli oggetti. – Creazione di un gioco con SDL.NET

In fase di disegno degli oggetti, come potete immaginare, le cose si complicano un po’. Dobbiamo contare varie cose:

  • Dobbiamo generare un oggetto al secondo;
  • Spostare la moglie una volta al secondo;
  • Capire se abbiamo preso l’oggetto in caduta oppure no, quindi segnare i punti o togliere le vite.

Iniziamo quindi con il codice, stavolta completo, di UpdatePartita().

[code]]czozMDczOlwiDQpwcml2YXRlIHZvaWQgVXBkYXRlUGFydGl0YSgpDQogICAgICAgIHsNCiAgICAgICAgICAgIHN3aXRjaCAoc3RhdG97WyYqJl19X3ApDQogICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgY2FzZSBTdGF0b1BhcnRpdGEuUHJpbWE6DQogICAgICAgICAgICAgIHtbJiomXX0gICAgICBWaWRlby5TY3JlZW4uQmxpdChiYWNrZyk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJle1smKiZdfW5kZXIoXCJQdW50ZWdnaW86IDBcIiwgU3lzdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNntbJiomXX0wLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlByZW1pIEludmlvIHBlciBpbntbJiomXX1pemlhcmUgbGEgcGFydGl0YS4uLlwiLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qb2ludHtbJiomXX0oNjAsIDE3KSk7DQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGYxLlJlbmRlcihcIlZpdGU6IDBcIiwgU3lzdGV7WyYqJl19bS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBvaW50KDQwMCwgMikpOw0KICAgICAgICAgICAgICAgIHtbJiomXX0gICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5JbkNvcnNvOg0KICAgICAgICAgICAgICAgICAge1smKiZdfSAgVmlkZW8uU2NyZWVuLkJsaXQoYmFja2cpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXJ7WyYqJl19KFwiUHVudGVnZ2lvOiBcIiArIHB1bnRlZ2dpby5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0e1smKiZdfWVtLkRyYXdpbmcuUG9pbnQoNjAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZGVyKFwie1smKiZdfVZpdGU6IFwiICsgdml0ZS5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qe1smKiZdfW9pbnQoNDAwLCAyKSk7DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKHBvc2l6aW9uZV97WyYqJl19Z2lvY2F0b3JlKQ0KICAgICAgICAgICAgICAgICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDA6DQogICAgICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KGdpb2MxLCBwb3NpemlvbmlfZ2lvY2F0b3JlW3Bvc2l6aW9uZV9ne1smKiZdfWlvY2F0b3JlXSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQoNCiAgICAgICAgICAgICAgICAgICAgICAgIGN7WyYqJl19YXNlIDE6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZ2lvYzIsIHBvc2l6aW9uaV9naW9jYXtbJiomXX10b3JlW3Bvc2l6aW9uZV9naW9jYXRvcmVdKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCg0KICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgIGNhc2UgMjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChnaW9jMyx7WyYqJl19IHBvc2l6aW9uaV9naW9jYXRvcmVbcG9zaXppb25lX2dpb2NhdG9yZV0pOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZXtbJiomXX1hazsNCiAgICAgICAgICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5CbGl0KHdpZmUsIHBve1smKiZdfXNpemlvbmlfbW9nbGllW3Bvc2l6aW9uZV9tb2dsaWVdKTsNCg0KICAgICAgICAgICAgICAgICAgICBVcGRhdGVPZ2dldHRpKCk7DQp7WyYqJl19DQogICAgICAgICAgICAgICAgICAgIGZvcmVhY2ggKE9nZ2V0dG9DYWRlbnRlIG8xIGluIG9nZ2V0dGkpDQogICAgICAgICAgICAgIHtbJiomXX0gICAgICB7DQogICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKG8xLmZpbmVzdHJhKQ0KICAgICAgICAgICAgICAgICAgICAge1smKiZdfSAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDA6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZ7WyYqJl19aWRlby5TY3JlZW4uQmxpdChvMS5DYW52YXMsIHBvc2l6aW9uaV9maW5lc3RyYTFbbzEucG9zaXppb25lXSk7DQogICAgICAgICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDE6DQogICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChvMS5DYW52YXMsIHBvc2l6aW9uaV9maW5lc3RyYTJbbzEucG97WyYqJl19c2l6aW9uZV0pOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gICAgY2FzZSAyOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChvMS5DYW52YXMsIHBve1smKiZdfXNpemlvbmlfZmluZXN0cmEzW28xLnBvc2l6aW9uZV0pOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgICAgICAgICBicmVha3tbJiomXX07DQoNCiAgICAgICAgICAgICAgICBjYXNlIFN0YXRvUGFydGl0YS5GaW5lOg0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3Jle1smKiZdfWVuLkJsaXQoYmFja2cpOw0KICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChmMS5SZW5kZXIoXCJQdW50ZWdnaW86e1smKiZdfSBcIiArIHB1bnRlZ2dpby5Ub1N0cmluZygpLCBTeXN0ZW0uRHJhd2luZy5Db2xvci5CbGFjayksIG5ldyBTeXN0ZW0uRHJhd2luZy5Qe1smKiZdfW9pbnQoNjAsIDIpKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZGVyKFwiUGFydGl0YSBUZXJte1smKiZdfWluYXRhLCBwcmVtZXJlIEludmlvLi4uXCIsIFN5c3RlbS5EcmF3aW5nLkNvbG9yLkJsYWNrKSwgbmV3IFN5c3RlbS5EcmF3aW5nLlBve1smKiZdfWludCg2MCwgMTcpKTsNCiAgICAgICAgICAgICAgICAgICAgVmlkZW8uU2NyZWVuLkJsaXQoZjEuUmVuZGVyKFwiVml0ZTogMFwiLCBTeXtbJiomXX1zdGVtLkRyYXdpbmcuQ29sb3IuQmxhY2spLCBuZXcgU3lzdGVtLkRyYXdpbmcuUG9pbnQoNDAwLCAyKSk7DQogICAgICAgICAgICAge1smKiZdfSAgICAgICBicmVhazsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfQ0KXCI7e1smKiZdfQ==[[/code]

Stavolta l'aggiunta è più succosa: c'è il metodo UpdateOggetti() che analizzeremo a breve, ed il ciclo foreach(OggettoCadente o1 in oggetti). Partiamo da questo ciclo, chiariamolo bene e successivamente spiegheremo nel dettaglio il metodo sopraccitato.

[code]]czo3MDg6XCINCmZvcmVhY2ggKE9nZ2V0dG9DYWRlbnRlIG8xIGluIG9nZ2V0dGkpDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICB7WyYqJl19ICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKG8xLmZpbmVzdHJhKQ0KICAgICAgICAgICAgICAgICAgICAgICAgew0KICAgICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICBjYXNlIDA6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvLlNjcmVlbi5Ce1smKiZdfWxpdChvMS5DYW52YXMsIHBvc2l6aW9uaV9maW5lc3RyYTFbbzEucG9zaXppb25lXSk7DQogICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19ICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDE6DQogICAgICAgICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChvMS5DYW52YXMsIHBvc2l6aW9uaV9maW5lc3RyYTJbbzEucG9zaXppb25lXSk7DQoge1smKiZdfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDI6DQp7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWaWRlby5TY3JlZW4uQmxpdChvMS5DYW52YXMsIHBvc2l6aW9uaV9maW5lc3tbJiomXX10cmEzW28xLnBvc2l6aW9uZV0pOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICB9DQogICAgICAgICAgICAgICB9DQpcIjt7WyYqJl19[[/code]

Questo blocco di codice scorre tutti gli elementi della lista di oggetti che stiamo usando: in poche parole, contiene tutte le informazioni degli oggetti che stanno cadendo dalle finestre. Per ogni oggetto, quindi, eseguiamo due operazioni specifiche:

  • Controlliamo da quale finestra sta cadendo, tramite il blocco switch(o1.finestra);
  • Disegnamo su schermo l'oggetto tramite la funzione Blit, usando come surface quella dell'oggetto attualmente preso in considerazione e come coordinate quelle della finestra dalla quale sta cadendo.

Avendo un percorso suddiviso in tre “parti”, ogni oggetto verrà disegnato nella parte indicata dalla variabile “o1.posizione”. Spero di essere stato chiaro, non potevo semplificare di più :) Adesso ci rimane solo da analizzare la funzione UpdateOggetti(). Prestate la massima attenzione soprattutto in questa parte.

Innanzitutto, ecco il codice completo del metodo:

[code]]czoxNTIwOlwiDQp2b2lkIFVwZGF0ZU9nZ2V0dGkoKQ0KICAgICAgICB7DQogICAgICAgICAgICBmcmFtZXMrKzsNCg0KICAgICAgICB7WyYqJl19ICAgIGlmIChmcmFtZXMgPT0gZnJhbWVsaW1pdCkNCiAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICBzMS5QbGF5KCk7DQoNCntbJiomXX0gICAgICAgICAgICAgICAgaW50IGZpbmVzdHJhID0gcjEuTmV4dCgwLCAzKTsNCiAgICAgICAgICAgICAgICBpbnQgaW5kaWNlID0ge1smKiZdfS0xOw0KDQogICAgICAgICAgICAgICAgcG9zaXppb25lX21vZ2xpZSA9IGZpbmVzdHJhOw0KDQogICAgICAgICAgICAgICAgZm9yZWF7WyYqJl19Y2ggKE9nZ2V0dG9DYWRlbnRlIG8xIGluIG9nZ2V0dGkpDQogICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICBzd3tbJiomXX1pdGNoIChvMS5wb3NpemlvbmUpDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgMDoNe1smKiZdfQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDE6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbzEucG9zaXppb25lKyt7WyYqJl19Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAyOg0KICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgICBpZiAobzEuZmluZXN0cmEgPT0gcG9zaXppb25lX2dpb2NhdG9yZSkNCiAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdW50ZWdnaW8gKz0gMTA7DQogICAgICB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlDQogICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdml0ZSAtPSAxOw0KICAgICAgICAgICAgICAgICAge1smKiZdfSAgICAgICAgICAgICAgczIuUGxheSgpOw0KDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2aXRlID09IDApIHN7WyYqJl19dGF0b19wID0gU3RhdG9QYXJ0aXRhLkZpbmU7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICAgICBpbmRpY2UgPSBvZ2dldHRpLkluZGV4T2YobzEpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFre1smKiZdfTsNCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgICAgIGlmKGluZGljZSAhPSB7WyYqJl19LTEpIG9nZ2V0dGkuUmVtb3ZlQXQoaW5kaWNlKTsNCiAgICAgICAgICAgICAgICBvZ2dldHRpLkFkZChuZXcgT2dnZXR0b0NhZGVudHtbJiomXX1lKHBvc2l6aW9uZV9tb2dsaWUsIHIxLk5leHQoMCwgNikpKTsNCg0KICAgICAgICAgICAgICAgIGZyYW1lcyA9IDA7DQoNCiAgICAge1smKiZdfSAgICAgICAgICAgaWYgKChwdW50ZWdnaW8gJSAzMDAgPT0gMCkmJihwdW50ZWdnaW8gIT0gMCkpDQogICAgICAgICAgICAgICAgew17WyYqJl19CiAgICAgICAgICAgICAgICAgICAgZnJhbWVsaW1pdCAtPSA1Ow0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCiAgIHtbJiomXX0gICAgIH0NClwiO3tbJiomXX0=[[/code]

Non vi preoccupate se non capite, può essere comprensibile: spiegherò tutto riga per riga.

Innanzitutto vi rispiego brevemente il ragionamento che ho fatto e che ho applicato: ogni secondo devono succedere diverse cose. Dobbiamo far proseguire gli oggetti nella loro caduta, dobbiamo spostare la moglie in una finestra a caso delle tre e dobbiamo creare un nuovo oggetto.

Quindi la prima riflessione da fare sta qua: dato che la cosa dovrà avvenire ogni secondo e che il nostro programma va a 60 frames al secondo, se usiamo la variabile "frames" come contatore ad ogni esecuzione del metodo UpdateOggetti(), quando "frames" avrà un valore pari a 60 sapremo che sarà passato esattamente un secondo. Questo è il senso dell'istruzione

frames++;

deve essere una sorta di "timer" molto grezzo e adattato a questo singolo scopo. La variabile "framelimit" invece serve a specificare la lunghezza dell'intervallo. Inizialmente avremo bisogno di determinate azioni ogni secondo? Allora il "framelimit" sarà pari a 60. Per velocizzare questi eventi ed aumentare la difficoltà del prodotto sarà sufficiente diminuire di un tot la variabile "framelimit".

Niente di più. Tenete bene a mente questo concetto. Proseguiamo con il codice:

if (frames == framelimit)


serve a specificare che tutto il contenuto di questo blocco if sarà svolto solo al raggiungimento di 60 frames. Ovvero, una volta al secondo. Ma cosa abbiamo deciso di svolgere? Ecco riga per riga tutto spiegato.

s1.Play();

è il suono del bip classico di questi giochini. Non c'è molto da spiegare, il suo uso è puramente estetico e viene riprodotto ogni volta che le cose nel gioco cambiano...

int finestra = r1.Next(0, 3);

int indice = -1;

posizione_moglie = finestra;


alla variabile finestra associamo invece il valore generato dal Random r1, tra 0 e 3. L'indice è una variabile che scopriremo tra poco, mentre la terza istruzione, semplicemente assegna a posizione_moglie il valore generato dal random.

Rileggere il proprio codice fa sempre bene: in questo caso infatti potevo tranquillamente assegnare il valore del random a posizione_moglie, eliminando la necessità di "finestra".

Adesso che abbiamo calcolato la nuova posizione della moglie, preoccupiamoci di gestire tutti gli oggetti:

[code]]czo4ODg6XCINCmZvcmVhY2ggKE9nZ2V0dG9DYWRlbnRlIG8xIGluIG9nZ2V0dGkpDQogICAgICAgICAgICAgICAgew0KICAgICAgICB7WyYqJl19ICAgICAgICAgICAgc3dpdGNoIChvMS5wb3NpemlvbmUpDQogICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICBjYXNlIDA6DQogICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDE6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAge1smKiZdfW8xLnBvc2l6aW9uZSsrOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgICAgICAgICAgICB7WyYqJl19IGNhc2UgMjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobzEuZmluZXN0cmEgPT0gcG9zaXppb25lX2dpb2NhdG9yZXtbJiomXX0pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdW50ZWdnaW8ge1smKiZdfSs9IDEwOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlDQogICB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICAgIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdml0ZSAtPSAxOw0KICAgIHtbJiomXX0gICAgICAgICAgICAgICAgICAgICAgICAgICAgczIuUGxheSgpOw0KDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlme1smKiZdfSAodml0ZSA9PSAwKSBzdGF0b19wID0gU3RhdG9QYXJ0aXRhLkZpbmU7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICB7WyYqJl19ICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRpY2UgPSBvZ2dldHRpLkluZGV4T2YobzEpOw0KICAgICAgICAgICAgICAgICAgIHtbJiomXX0gICAgICAgICBicmVhazsNCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIH0NClwiO3tbJiomXX0=[[/code]

Come punto di riferimento per capire cosa succede dobbiamo utilizzare la posizione attuale di ogni oggetto. Per questo, con il ciclo foreach, prendiamo in considerazione ogni oggetto attualmente presente in lista.

Nel caso la posizione dell'oggetto attualmente preso in considerazione sia 0 oppure 1, c'è ben poco da fare: lo si sposta in giù di uno. A questo serve l'istruzione o1.posizione++.

Nel caso invece la posizione sia 2, quindi ad un passo dal giocatore, abbiamo questo blocco if.

[code]]czoxOTc6XCINCmlmIChvMS5maW5lc3RyYSA9PSBwb3NpemlvbmVfZ2lvY2F0b3JlKQ0Kew0KICAgIHB1bnRlZ2dpbyArPSAxMDsNCn17WyYqJl19DQplbHNlDQp7DQogICAgdml0ZSAtPSAxOw0KICAgIHMyLlBsYXkoKTsNCg0KICAgIGlmICh2aXRlID09IDApIHN0YXRvX3AgPSBTdHtbJiomXX1hdG9QYXJ0aXRhLkZpbmU7DQp9DQppbmRpY2UgPSBvZ2dldHRpLkluZGV4T2YobzEpOw0KXCI7e1smKiZdfQ==[[/code]

Nel caso il giocatore si trovi sotto l'oggetto (la finestra appartenente all'oggetto può essere 0,1 o 2. idem per la posizione del giocatore) allora viene aumentato il punteggio di dieci punti. L'oggetto è stato preso con successo.

Nel caso contrario invece le cose cambiano. Togliamo una vita con vite -= 1; e riproduciamo s2, il suono che si utilizza nel caso si perda una vita. Infine facciamo un ultimo controllo: se le vite sono pari a zero allora il gioco finisce. Basta quindi dare un nuovo valore a stato_p: StatoPartita.Fine.

Infine ecco che introduciamo qualche informazione in più sulla variabile intera "indice". Normalmente non possiamo cancellare un oggetto dentro un ciclo che scorre l'oggetto stesso, non trovate? Parliamo della nostra lista di oggetti.

Ogni secondo infatti, un nuovo oggetto deve essere creato. Non possiamo accumulare oggetti all'infinito però! Per cui dobbiamo cancellare anche l'oggetto che è già caduto. A questo serve l'indice, che assume il valore di ritorno del metodo oggetti.IndexOf(o1), che indica la posizione dell'oggetto o1 nella lista.

Le cose tuttavia non finiscono qua:

[code]]czoyMDU6XCINCmlmKGluZGljZSAhPSAtMSkgb2dnZXR0aS5SZW1vdmVBdChpbmRpY2UpOw0Kb2dnZXR0aS5BZGQobmV3IE9nZ2V0dG97WyYqJl19Q2FkZW50ZShwb3NpemlvbmVfbW9nbGllLCByMS5OZXh0KDAsIDYpKSk7DQoNCmZyYW1lcyA9IDA7DQoNCmlmICgocHVudGVnZ2lvIHtbJiomXX0lIDMwMCA9PSAwKSYmKHB1bnRlZ2dpbyAhPSAwKSkNCnsNCiAgICBmcmFtZWxpbWl0IC09IDU7DQp9DQpcIjt7WyYqJl19[[/code]

Come prima cosa controlliamo che l'indice sia diverso da -1.

Domanda: perchè questo controllo?
Risposta: la variabile indice ha il compito che abbiamo spiegato sopra. Tuttavia, nei primi due secondi di gioco, gli oggetti sono in caduta e ce ne sono precisamente 2. Nessuno di questi, inoltre, è a contatto col giocatore. In questo modo, finchè non c'è un indice "valido" (ovvero diverso da zero) non verrà cancellato nessun'oggetto.

In questo modo appena avremo tre oggetti in campo (e la posizione del primo oggetto sarà 2, guardacaso proprio ad un passo dal giocatore) allora avremo un nuovo indice ed eseguiremo le operazioni nel blocco.

"oggetti.RemoveAt(indice)" è l'operazione che fa per noi. Dalla lista oggetti elimineremo quindi l'oggetto all'indice specificato nell'argomento.

Dopo aver rimosso l'oggetto, ne creiamo uno nuovo:

oggetti.Add(new OggettoCadente(posizione_moglie, r1.Next(0, 6)));

con questa sintassi abbiamo creato un nuovo oggetto cadente, passando come parametri del costruttore, nell'ordine, la posizione attuale della moglie e un nuovo valore generato a caso tra 1 e 6. Scrivo 1 anzichè zero perchè quando specifichiamo il margine inferiore è considerato escluso. L'istruzione new OggettoCadente(...) è a sua volta argomento di oggetti.Add(). In questo modo l'oggetto viene aggiunto alla lista.

Tramite "frames = 0;" il contatore del nostro grezzissimo timer viene azzerato e le operazioni ripartono da capo.

Infine, ecco le istruzioni che permettono di velocizzare il gioco man mano che si va avanti:

[code]]czo3NzpcIg0KaWYgKChwdW50ZWdnaW8gJSAzMDAgPT0gMCkmJihwdW50ZWdnaW8gIT0gMCkpDQp7DQogICAgZnJhbWVsaW1pdCAtPSB7WyYqJl19NTsNCn0NClwiO3tbJiomXX0=[[/code]

con queste poche righe di codice viene innanzitutto controllato che il punteggio attuale sia un multiplo di 300 (avevamo deciso che ogni 300 punti la velocità venisse aumentata: basterà controllare che il punteggio attuale sia un multiplo dello stesso numero specificato) e che ovviamente sia diverso da zero, in modo tale da non velocizzare tutto all'inizio. Se le condizioni sopraccitate vengono rispettate, allora il limite dettato da "framelimit" viene diminuito di cinque frames.

Per spiegarlo in parole povere, fin quando non faremo 300 punti avremo un framelimit di 60. Da 300 punti a 600 avremo un framelimit di 55, e così via, di trecento in trecento diminuendo di 5.

Ce l'abbiamo fatta! Dopo questa istruzione il nostro metodo è completato e non abbiamo bisogno di altre istruzioni aggiuntive... ora che la fase di disegno è completata al 100%, manca ancora da gestire l'input. Infine, metteremo tutto insieme.

Avanti!

  • Share/Bookmark

Disegnamo il Background. – Creazione di un gioco con SDL.NET

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.

  • Share/Bookmark