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

Terza parte del tutorial dedicato alla creazione di un gioco completo. In questa parte verrà gestita la grafica relativa allo sfondo.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

Introduzione

In questo articolo vedremo come gestire lo sfondo, in particolare renderlo animato per gestire in maniera più accattivante lo spostamento dell’immagine.
Si creano tre sfondi di diverso stile, per esempio come quelli riportati in figura 1 figura 2 e figura 3




Figura 1




Figura 2






Figura 3


Creazione della classe sfondo

Si crea una classe per la gestione dello sfondo, dalla finestra esplora soluzione facciamo click con il tasto destro sul nome del progetto, e selezioniamo dal progetto “Aggiungi” e successivamente “Nuovo Elemento”.
Selezioniamo classe ed impostiamo il nome “Sfondo” come nome della classe”.
Aggiungiamo lo spazio dei nomi relativi a “Framework” e “Framework.Graphics” il tutto come riportato qui di seguito

//per la calsse texture
using Microsoft.Xna.Framework.Graphics;
//per la classe vectory2
using Microsoft.Xna.Framework;

Nella classe scriviamo i membri per la gestione dell’immagine la posizione dei pixel e la velocità di spostamento, inoltre aggiungiamo tre metodi, per l’inizializzazione, la visualizzazione a video e l’aggiornamento costante
Qui di seguito si riporta tale dichiarazione..


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//per la calsse texture
using Microsoft.Xna.Framework.Graphics;
//per la classe vectory2
using Microsoft.Xna.Framework;
namespace XNATutorial
{
    class Sfondo
    {
        //gestione immagine sfondo
        Texture2D texture;
        //posizione dei pixel dells sfondo
        Vector2[] posizione;
        //velocità di spostamento delle immagini
        int Velocita;
        public void Initialize()
        {
        }
        public void Update()
        {
        }
        public void Draw()
        {
        }
    }
}


Il metodo initialize lo modifichiamo, in modo che imposta la posizione dell’immagine e la velocità di spostamento, qui di seguito si riporta il codice di tale modifica.

public void Initialize(ContentManager contenuto, String ImgPath, int Larghezza, int velocita)
        {
            //carica l'immagine di sfondo
            texture = contenuto.Load<Texture2D>(ImgPath);
            //imposto la velocità di spostamento
            this.Velocita = velocita;
            // per le dimensione dello sfondo
            posizione = new Vector2[Larghezza / texture.Width + 1];
           //imposto la posizione iniziale
            for (int i = 0; i < posizione.Length; i++)
            {
                posizione[i] = new Vector2(i * texture.Width, 0);
            }
        }


Ora modifichiamo il metodo update, per la gestione della visualizzazione dell’immagine, in riferimento alla velocità, spostandolo a destra e sinistra.
Qui di seguito si riporta la modifica al metodo update.

 public void Update()
        {
            //aggiorno la  posizione
            for (int i = 0; i < posizione.Length; i++)
            {
                //incremento la poszione in riferimento alla velocita
                posizione[i].X += Velocita;
                // verifico la velocità e sposto a sinistra
                if (Velocita <= 0)
                {
                    //verifico se è stata visualizzata alla fine dello schermo
                    if (posizione[i].X <= -texture.Width)
                    {
                        posizione[i].X = texture.Width * (posizione.Length - 1);
                    }
                }
                //sposto a destra lo sfondo
                else
                {
                    //imposto la posizione parte destra
                    if (posizione[i].X >= texture.Width * (posizione.Length - 1))
                    {
                        posizione[i].X = -texture.Width;
                    }
                }
            }
        }

Ora non ci resta che modificare il metodo Draw, per visualizzare a video la nuova impostazione grafica.
Si riporta il codice del metodo draw.

 public void Draw(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < posizione.Length; i++)
            {
                spriteBatch.Draw(texture, posizione[i], Color.White);
            }
        }

A questo punto la creazione della classe sfondo è terminata, qui di seguito si riporta il codice completo di tale classe.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//per la calsse texture
using Microsoft.Xna.Framework.Graphics;
//per la classe vectory2
using Microsoft.Xna.Framework;
//per la gestione del ContentManager
using Microsoft.Xna.Framework.Content;
namespace XNATutorial
{
    class Sfondo
    {
        //gestione immagine sfondo
        Texture2D texture;
        //posizione dei pixel dells sfondo
        Vector2[] posizione;
        //velocità di spostamento delle immagini
        int Velocita;
        public void Initialize(ContentManager contenuto, String ImgPath, int Larghezza, int velocita)
        {
            //carica l'immagine di sfondo
            texture = contenuto.Load<Texture2D>(ImgPath);
            //imposto la velocità di spostamento
            this.Velocita = velocita;
            // per le dimensione dello sfondo
            posizione = new Vector2[Larghezza / texture.Width + 1];
            //imposto la posizione iniziale
            for (int i = 0; i < posizione.Length; i++)
            {
                posizione[i] = new Vector2(i * texture.Width, 0);
            }
        }
        public void Update()
        {
            //aggiorno la  posizione
            for (int i = 0; i < posizione.Length; i++)
            {
                //incremento la poszione in riferimento alla velocita
                posizione[i].X += Velocita;
                // verifico la velocità e sposto a sinistra
                if (Velocita <= 0)
                {
                    //verifico se è stata visualizzata alla fine dello schermo
                    if (posizione[i].X <= -texture.Width)
                    {
                        posizione[i].X = texture.Width * (posizione.Length - 1);
                    }
                }
                //sposto a destra lo sfondo
                else
                {
                    //imposto la posizione parte destra
                    if (posizione[i].X >= texture.Width * (posizione.Length - 1))
                    {
                        posizione[i].X = -texture.Width;
                    }
                }
            }        }
        public void Draw(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < posizione.Length; i++)
            {
                spriteBatch.Draw(texture, posizione[i], Color.White);
            }
        }
    }
}


Passiamo alla classe game1,  in cui andremo ad utilizzare la nuova classe appena creata.
Aggiungiamo nel content le tre immagini, facciamo click con il tasto destro e selezioniamo “aggiungi” e successivamente elemento esistente.
Terminata l’aggiunta delle immagini, dobbiamo creare dei membri per gestire le tre immagini.
Si crea un oggetto di tipo Texture2D per lo sfondo principale, e due oggetti della classe precedentemente creata per i due sfondi.

 Qui di seguito si riporta tale dichiarazione.

//immagine principale
        Texture2D SfondoPrincipale;
        //gestione delle immagini di sfondo quelle in movimento
        Sfondo sfondo1;
        Sfondo sfondo2;

Nell’evento Initialize, andiamo a scrivere il codice per inizializzare i due oggetti di tipo sfondo.
Qui di seguito si riporta il codice dell’evento initialize.

protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            // inizializzo la classe
            player = new Player();
            //imposto la velocità
            VelocitaSpostamento = 8.0f;
            //oggetti per la gestione dello sfondo
            sfondo1 = new Sfondo();
            sfondo2 = new Sfondo();
            base.Initialize();
        }

Nell’evento loadcontent, scriviamo il codice per caricare gli oggetti immagini, qui di si riporta il codice per l’evento loadcontent

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);
            //carico le immagini
            sfondo1.Initialize(Content, "Sfondo1", GraphicsDevice.Viewport.Width, -1);
            sfondo2.Initialize(Content, "Sfondo2", GraphicsDevice.Viewport.Width, -2);
            SfondoPrincipale = Content.Load<Texture2D>("SfondoPriincipale");
            // TODO: use this.Content to load your game content here
        }
 

Nell’evento update, dopo l’invocazione del metodo updateplayer  scriviamo il codice per eseguire il metodo update degli oggetti di tipo sfondo.

Riportiamo il codice per il metodo update.


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();
            //aggiorno il gaming
            UpdatePlayer(gameTime);
            //aggiorno la posizione delle immagini
            sfondo1.Update();
            sfondo2.Update();
            base.Update(gameTime);
        }


Ora non ci resta che aggiornare la visualizzazione a video, nel metodo draw scriviamo il codice dopo l’invocazione del metodo begin dell’oggetto spritebatch.
Si utilizza il metodo draw di tale oggetto per impostare lo sfondo e il metodo draw degli oggetti di tipo sfondo.

protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            // TODO: Add your drawing code here
            //ridisegno il tutto
            spriteBatch.Begin();
            spriteBatch.Draw(SfondoPrincipale, Vector2.Zero, Color.White);
            //visualizzo lo spostamento
            sfondo1.Draw(spriteBatch);
            sfondo2.Draw(spriteBatch);
            //aggiorno la visualizzazione
            player.Draw(spriteBatch);
            //termine del ridisegno
            spriteBatch.End();
            base.Draw(gameTime);
        }
 

L’effetto sarà come mostrato in figura 4.





Figura 4


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;
        //immagine principale
        Texture2D SfondoPrincipale;
        //gestione delle immagini di sfondo quelle in movimento
        Sfondo sfondo1;
        Sfondo sfondo2;
        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;
            //oggetti per la gestione dello sfondo
            sfondo1 = new Sfondo();
            sfondo2 = new Sfondo();
            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);
            //carico le immagini
            sfondo1.Initialize(Content, "Sfondo1", GraphicsDevice.Viewport.Width, -1);
            sfondo2.Initialize(Content, "Sfondo2", GraphicsDevice.Viewport.Width, -2);
            SfondoPrincipale = Content.Load<Texture2D>("SfondoPriincipale");
            // 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();
            //aggiorno il gaming
            UpdatePlayer(gameTime);
            //aggiorno la posizione delle immagini
            sfondo1.Update();
            sfondo2.Update();
            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();
            spriteBatch.Draw(SfondoPrincipale, Vector2.Zero, Color.White);
            //visualizzo lo spostamento
            sfondo1.Draw(spriteBatch);
            sfondo2.Draw(spriteBatch);
            //aggiorno la visualizzazione
            player.Draw(spriteBatch);
            //termine del ridisegno
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

Conclusioni

L'articolo ha fornito altre informazioni e tecniche utili sulla grafica. In questa parte si è visto la gestione dello sfondo, utile in quei scenari in cui dobbiamo applicare determinati effetti.
Tramite la parola download potete scaricare il file di progetto sviluppato in questi primi capitoli.

Download