Tutorial XNA creazione gioco : Tutorial XNA creazione di un gioco completo parte 2

Continua il tutorial dedicato alla creazione di un gioco completo. In questa parte vedremo come applicare alcuni effetti grafici al nostro gioco.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

Introduzione

Continua il percorso formativo sulla creazione di un video gioco completo in XNA, in questa parte vedremo come rendere l’astronave animata, tramite l’effetto di spostamento.
In particolare, vedremo come la parte grafica relativa al fuoco del carburante, cambia forma, permettendo un effetto di oggetto in movimento.
Prima di tutto bisogna creare un immagine, composta da tante immagine, una serie di frame,  il tutto come mostrato in figura 1.




Figura 1

Il gioco che andremo a creare è come illustrato in figura 2, la stessa navicella della prima parte, ma con effetto animazione.





Figura 2

Creazione del gioco

Riprendendo il tutorial della prima parte, aggiungiamo una nuova classe, denominata animazione.
Dalla finestra di Esplora soluzione,  facciamo click con il tasto destro del mouse, sul nome del progetto, e selezioniamo nuova classe.
La classe la chiamiamo Animazione (file Animazione.cs).


In questa classe abbiamo membri e proprietà per la gestione delle singole immagini (frame) i tempi per la visualizzazione, ed il posizionamento.
I metodi della classe, gestiscono varie attività, una permette di impostare  i valori delle varie variabili (metodo initialize) un metodo per la visualizzazione dell’immagine a video (draw) e l’aggiornamento costante (update).
Qui di seguito si riporta il codice completo di tale classe, commentato.

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Spazio di nomi - textbure2d
using Microsoft.Xna.Framework.Graphics;
//spazio di nomi per il colore e rectangle
using Microsoft.Xna.Framework;
namespace XNATutorial
{
    class Animazione
    {
        // insieme d'immagine animazione
        Texture2D textureInsiemeImmagini;
        //per la visualizzazione del singolo frame
        float scala;
        //indica il tempo che è passato
        int TempoTrascorso;
        //tempo per la visualizzazione di ogni singolo frame
        int frameDurata;
        // numero dei frame (immagini)
        int frameTotali;
        //indice del frame corrente da visualizzare
        int frameCorrente;
       //colore del framew da visualizzare
        Color colore;
        //area per la visualizzazone dell'immagine
        Rectangle areaRect = new Rectangle();
        //oggetto per la definizione dell'area di destinazione delle immagini
        Rectangle AreaDestinazioneRect = new Rectangle();
        //larghezza framew
        public int FrameWidth;
        //altezzaFrame
        public int FrameHeight;
        //Stato Attivo Animazione
        public bool statoAttivo;
        //determina se attivare l'animazione oppure no
        public bool AttivaDisattivare;
        //posizione
        public Vector2 Posizione;
        public void Initialize(Texture2D texture, Vector2 posizione, int frameWidth, int frameHeight, int Frametotali, int FrameCorrente, Color Colore, float Scala, bool AttivaDisattiva)
        {
            //inizializzo i vari oggetti
            this.colore = Colore;
            this.FrameWidth = frameWidth;
            this.FrameHeight = frameHeight;
            this.frameTotali = Frametotali;
            this.frameDurata = FrameCorrente;
            this.scala = Scala;
            AttivaDisattivare = AttivaDisattiva;
            Posizione = posizione;
            textureInsiemeImmagini = texture;
            //imposto il tempo delle animazione
            TempoTrascorso = 0;
            frameCorrente = 0;
            //attivo l'animazione
            statoAttivo = true;
        }
        public void Update(GameTime gameTime)
        {
            //Verifico lo stato attivo se animare o no il game
            if (statoAttivo == false)
                return;
            //aggiorno il tempo trascorso
            TempoTrascorso += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
            // In caso che ho tempo per il singolo frame è passato, passo all'immagine successiva
            if (TempoTrascorso > frameDurata)
            {
                //passo al frame successivo
                frameCorrente++;
                // se il frame corrente è la fine di tutto l'insieme lo riporto all'inzio
                if (frameCorrente == frameTotali)
                {
                    frameCorrente = 0;
                    //verifico se attivare o no il games
                    if (AttivaDisattivare == false)
                        statoAttivo = false;
                }
                //reimposto il tempo trascorso per il successivo frame
                TempoTrascorso = 0;
            }
            //ottengo l'area per la visualizzazione delle immagini
            areaRect = new Rectangle(frameCorrente * FrameWidth, 0, FrameWidth, FrameHeight);
            //imposto l'area per il posizionamento dell'immagine
            AreaDestinazioneRect = new Rectangle((int)Posizione.X - (int)(FrameWidth * scala) / 2,
            (int)Posizione.Y - (int)(FrameHeight * scala) / 2,
            (int)(FrameWidth * scala),
            (int)(FrameHeight * scala));
        }
        //Metodo per visualizzare a video l'immagine
        public void Draw(SpriteBatch spriteBatch)
        {
            //solo nel caso che lo stato è attivo
            if (statoAttivo)
            {
                spriteBatch.Draw(textureInsiemeImmagini, AreaDestinazioneRect, areaRect, colore);
            }
        }
    }
}


Modifica Classe player

Terminata la creazione della classe animazione, passiamo alla classe Player, questa classe, già creata nella prima parte, si aggiunge un oggetto di tipo classe Animazione.
Dichiariamo a livello di classe, un oggetto di tipo “Animazione” relativa alla classe precedente.
Qui di seguito tale dichiarazione.

//oggetto per la classe animazione
        public Animazione PlayerAnimazione;

Ridefiniamo le proprietà relativa alla larghezza ed altezza dell’immagine, utilizzando l’oggetto PlayerAnimazione, in questo modo, prenderà i valori relativi ad altezza e larghezza.
Qui di seguito tale modifica.

//larghezza per il posizionamento
        public int Width
        {
            get { return PlayerAnimazione.FrameWidth; }
        }
        //altezza per il posizionamento
        public int Height
        {
            get { return PlayerAnimazione.FrameHeight; }
        }


Il metodo “Initialize”, sostituiamo la dichiarazione dell’oggetto player, con questo nuovo relativo alla classe animazione.
Qui di seguito tale dichiarazione.

// PlayerTexture = texture;
            //inizializzo l'oggetto
            PlayerAnimazione = animazione;


Modifichiamo il metodo Update, impostando un parametro, relativo ad un oggetto di tipo GameTime, e impostando le proprietà “Posizione” con le nuove informazioni.
Qui di seguito tale modifiche.

public void Update(GameTime gameTime)
        {
            PlayerAnimazione.Posizione = Posizione;
            PlayerAnimazione.Update(gameTime);
        }
 

Modifichiamo il metodo Draw, utilizzando il metodo “Draw” della classe animazione.
Qui di seguito tale modifiche.

 public void Draw(SpriteBatch spriteBatch)
        {
           // spriteBatch.Draw(PlayerTexture, Posizione, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
            PlayerAnimazione.Draw(spriteBatch);
        }

Si riporta il codice completo della classe Player.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//per la classe texture2d
using Microsoft.Xna.Framework.Graphics;
//per la classe Vector2
using Microsoft.Xna.Framework;
namespace XNATutorial
{
    class Player
    {
        // per gestire l'oggetto
        public Texture2D PlayerTexture;
        // per la posizione
        public Vector2 Posizione;
        // stato
        public bool StatoAttivo;
        // totale carburante
        public int Carburante;
        //oggetto per la classe animazione
        public Animazione PlayerAnimazione;
        //larghezza per il posizionamento
        //commento
        //public int Width
        //{
        //    get { return PlayerTexture.Width; }
        //}
        //larghezza per il posizionamento
        public int Width
        {
            get { return PlayerAnimazione.FrameWidth; }
        }
        //altezza per il posizionamento
        public int Height
        {
            get { return PlayerAnimazione.FrameHeight; }
        }
        //altezza per il posizionamento
        //public int Height
        //{
        //    get { return PlayerTexture.Height; }
        //}
        //modifico da Texture2D texture in Animazione animation
        public void Initialize(Animazione animazione, Vector2 posizione)
        {
           // PlayerTexture = texture;
            //inizializzo l'oggetto
            PlayerAnimazione = animazione;
            // imposto la posizione
            Posizione = posizione;
            //imposto lo stato in true quindi attivo
            StatoAttivo = true;
            //imposto il punteggio
            Carburante = 100;
        }
        //gestione dell'immagine  update
        public void Update(GameTime gameTime)
        {
            PlayerAnimazione.Posizione = Posizione;
            PlayerAnimazione.Update(gameTime);
        }
        /// <summary>
        /// Funzione che permette di visualizzare a video il risultato
        /// </summary>
        /// <param name="spriteBatch"></param>
        public void Draw(SpriteBatch spriteBatch)
        {
           // spriteBatch.Draw(PlayerTexture, Posizione, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
            PlayerAnimazione.Draw(spriteBatch);
        }
    }
}


Classe Game1

Passiamo alla classe game1 apportando le modifiche inserendo l'utilizzo della nuova classe.
In esplora soluzione, facciamo click sulla sezione “Content”  ed aggiungiamo l’immagine contenente diversi frame della nostra immagine.
Nell’evento LoadContent, scriviamo il codice per il caricamento della nostra immagine.
Il codice crea un oggetto di tipo Animazione, carica l’immagine animata (quella contenente più frame) e tramite il metodo Initialize, imposta i valori per i membri della classe animazione.


Qui di seguito si riporta il codice delle suddette operazioni

//oggetto per la gestione dell'effetto immagini in movimento
            Animazione playerAnimazione = new Animazione();
            Texture2D playerTexture = Content.Load<Texture2D>("AstronaveMovimento");
            playerAnimazione.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);

Nel metodo UpdatePlayer, utilizziamo il metodo update, dell’oggetto player con l’oggetto GameTime, qui di seguito si riporta tale dichiarazione.
 

//passo l'oggetto gametime
            player.Update(gameTime);

Qui di seguito si riporta il codice completo della classe Game1.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace XNATutorial
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //oggetto della classe Player
        Player player;
        //Per la gestione della tastiera
        KeyboardState StatoCorrenteTastiera;
        KeyboardState StatoPrecedenteTastiera;
        // la velocità di spostamento
        float VelocitaSpostamento;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            // inizializzo la classe
            player = new Player();
            //imposola velocità
            VelocitaSpostamento = 8.0f;
            base.Initialize();
        }
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            //oggetto per la gestione dell'effetto immagini in movimento
            Animazione playerAnimazione = new Animazione();
            Texture2D playerTexture = Content.Load<Texture2D>("AstronaveMovimento");
            playerAnimazione.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);
            // carico la risorsa (immagine)
            Vector2 playerPosizione = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y + GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
           //ricambio l'oggetto player
            player.Initialize(playerAnimazione, playerPosizione);
            // player.Initialize(Content.Load<Texture2D>("Astronave"), playerPosizione);
            // TODO: use this.Content to load your game content here
        }
        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            // TODO: Add your update logic here
            //tasto precedente prima di questa modifica          
            StatoPrecedenteTastiera = StatoCorrenteTastiera;
            //rilevo l'ultimo pulsante digitato
            StatoCorrenteTastiera = Keyboard.GetState();
            //Update the player
            UpdatePlayer(gameTime);
            base.Update(gameTime);
        }
        private void UpdatePlayer(GameTime gameTime)
        {
            //passo l'oggetto gametime
            player.Update(gameTime);
            //nel caso che digito il pulsante esc esco dal gioco
            if (StatoCorrenteTastiera.IsKeyDown(Keys.Escape))
                base.Exit();
            //in riferimento alle freccie della tastiera sposto l'astronave
            if (StatoCorrenteTastiera.IsKeyDown(Keys.Left) )
            {
                player.Posizione.X -= VelocitaSpostamento;
            }
            if (StatoCorrenteTastiera.IsKeyDown(Keys.Right) )
            {
                player.Posizione.X += VelocitaSpostamento;
            }
            if (StatoCorrenteTastiera.IsKeyDown(Keys.Up) )
            {
                player.Posizione.Y -= VelocitaSpostamento;
            }
            if (StatoCorrenteTastiera.IsKeyDown(Keys.Down) )
            {
                player.Posizione.Y += VelocitaSpostamento;
            }
            //imposto la posizione della navicella
            player.Posizione.X = MathHelper.Clamp(player.Posizione.X, 0, GraphicsDevice.Viewport.Width - player.Width );
            player.Posizione.Y = MathHelper.Clamp(player.Posizione.Y, 0, GraphicsDevice.Viewport.Height - player.Height + 50);
        }
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            // TODO: Add your drawing code here
            //ridisegno il tutto
            spriteBatch.Begin();
            //aggiorno la visualizzazione
            player.Draw(spriteBatch);
            //termine del ridisegno
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}



Conclusioni

Ora non ci resta che testare il nostro video gioco, vedremo l’effetto di movimento o meglio la parte relativa al fuoco che cambia.
L’immagine non è delle migliori, naturalmente nelle società informatiche in ogni progetto per la creazione di un video gioco, ci sono varie figure, come grafico, musicista, analista ed altri ruoli. Non avendo valida preprazione in grafica, è tutto quello che sono riuiscito a fare.
Tramite la parola download si può scaricare il progetto della prima e seconda parte.

Download