Introduzione
In questo articolo, vedremo come creare una semplice applicazione XNA che illustra come applicare un livello nel proprio gioco, l'articolo vuole fornire anche le basi dell'utilizzo dell'utilizzo delle librerie e dei progetti di tipo Content Pipeline Extension Library.
Dopo aver creato un nuovo progetto XNA (figura 1), aggiungete una nuova libreria, dalla finestra esplora soluzione, selezionare nuovo progetto, e tra i vari modelli selezionare “Windows Game Library” come riportato in figura 2.
Figura 1
Figura 2
Nella finestra di dialogo che viene aperta per la creazione di nuovo progetto, impostiamo nella casella nome, il nome “XNALivelloLibrary”, confermiamo il tutto tramite il pulsante "OK".
Nel progetto, eliminiamo il file class, il tutto come mostrato in figura 3.
Figura 3
Terminata tale operazione, non ci resta che creare il terzo progetto, è precisamente un “Content pipeline Extension library” , mettendo come nome “XNALivelloContentPipelineExLib” il tutto come illustrato nella figura 4.
Figura 4
Dal progetto, eliminiamo la classe “ContentProcessor1” che viene generata in automatico, il tutto come mostrato in figura 5.
Figura 5
Ora aggiungiamo i riferimenti tra i vari progetti, in quello relativo al gioco, aggiungiamo il riferimento alla libreria di livello, ossia al progetto “XNALivelloLibrary” , sempre nel progetto del gioco, nella parte Content, aggiungiamo il riferimento al progetto di tipo contentPipeline, ossia quello con il nome “XNALivelloContentiPipelineExLib” .
Nel progetto “XNALivelloContentPipelineExLib” il riferimento del progretto libreria, ossia “XNALivelloLibrary”.
In figura 6, sono riportati i vari riferimenti nei vari progetti.
Figura 6
Creazione della classe livello
Dopo aver creato la struttura del nostro video gioco, si creano le varie classi per i vari prrogetti.
Procediamo in ordine, creando una classe per la gestione del livello.
Nel progetto XNALivelloLibrary, si aggiunge una nuova classe, chiamata Livello.
Qui di seguito si riporta il codice completo di tale classe.
Questa classe presenta una variabile globale che contiene i valori, due metodi che restituiscono il valore totale delle righe e colonne.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace XNALivelloLibrary
{
//Rendiamo la classe pubblica
public class Livello
{
public int[,] Valori { get; set; }
//costruttore della classe
public Livello(int[,] valori)
{
Valori = valori;
}
/// <summary>
/// metodo che restituisce il valore della array
/// </summary>
/// <param name="riga"></param>
/// <param name="colonna"></param>
/// <returns></returns>
public int OttieniValore(int riga, int colonna)
{
return Valori[riga, colonna];
}
//ottiene il totale degli elementi presenti per la prima dimensione del array
public int Righe
{
get
{
return Valori.GetLength(0);
}
}
//ottiene il totale degli elementi presenti per la seconda dimensione del array
public int Colonne
{
get
{
return Valori.GetLength(1);
}
}
}
}
Terminata la creazione della classe passiamo alla classe relativa al progetto di tipo Content Pipeline Export Library, quello denominato “XNALivelloContentPipelineExLib “ .
In questo progetto si crea una nuova classe di tipo “Content Importer”, in cui gestiremo alcune informazioni.
Nella finestra “Esplora soluzione” si fa click sul nome del progetto “XNALivelloContentPipelineExlib” e si aggiunge un nuovo “Content Importer”, come illustrato in figura 7.
Figura 7.
Per il campo nome, impostiamo il valore “LivelloImporter”.
Modifichiamo la prima riga , quella relativa all’attributo della classe. Di default, troviamo il seguente codice.
[ContentImporter(".abc", DisplayName = "ABC Importer", DefaultProcessor = "AbcProcessor")]
La replichiamo nel seguente modo.
[ContentImporter(".livello", DisplayName = "Livello Importer", DefaultProcessor = "LivelloProcessor")]
La prima informazione, quella relativa con il punto “.Livello” definisce l’estensione del file, mentre il secondo valore, il nome del file, ed il terzo, nome classe.
Nel metodo import scriviamo il codice che restituisce il contenuto del file.
Qui di seguito si riporta il codice completo della classe.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
// TODO: replace this with the type you want to import.
using TImport = System.String;
namespace XNALivelloContentPipelineExLib
{
/// <summary>
/// This class will be instantiated by the XNA Framework Content Pipeline
/// to import a file from disk into the specified type, TImport.
///
/// This should be part of a Content Pipeline Extension Library project.
///
/// TODO: change the ContentImporter attribute to specify the correct file
/// extension, display name, and default processor for this importer.
/// </summary>
[ContentImporter(".livello", DisplayName = "Livello Importer", DefaultProcessor = "LivelloProcessor")]
public class LivelloImporter : ContentImporter<TImport>
{
public override TImport Import(string filename, ContentImporterContext context)
{
// TODO: read the specified file into an instance of the imported type.
return System.IO.File.ReadAllText(filename);
}
}
}
Questa classe ci permette di leggere le informazioni del file.
Sempre nel progetto “XNALivelloContentPipelineExLib” aggiungiamo un nuovo elemento, in particolare un “Content Processor”.
Dalla finestra esplora soluzioni, fate click tramite tasto destro del mouse, sul nomedel progetto e selezionate “Nuovo elemento”.
Nella finestra che viene visualizzata (figura 8) selezionate il modello “Content Processor”.
Figura 8
Nella caselle Name, impostate il valore “LivelloProcessor”.
Viene generata una classe con del codice.
Sostituiamo il codice relativo alla riga:
using TOutput = System.String;
In
using TOutput = XNALivelloLibrary.Livello;
In questo modo restituisce un oggetto di tipo livello, ossia la classe che si trova nel progetto XNALivelloLibrary.
Cambiamo la seguente riga di codice,
[ContentProcessor(DisplayName = "XNALivelloContentPipelineExLib.LivelloProcessor")]
Con il seguente frammento di codice
[ContentProcessor(DisplayName = "Livello Processor")]
Nel metodo “processor” scriviamo il codice che permette di recuperare i valori del file.
Qui di seguito si riporta il codice completo di tutta la classe.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
// TODO: replace these with the processor input and output types.
using TInput = System.String;
using TOutput = XNALivelloLibrary.Livello;
namespace XNALivelloContentPipelineExLib
{
/// <summary>
/// This class will be instantiated by the XNA Framework Content Pipeline
/// to apply custom processing to content data, converting an object of
/// type TInput to TOutput. The input and output types may be the same if
/// the processor wishes to alter data without changing its type.
///
/// This should be part of a Content Pipeline Extension Library project.
///
/// TODO: change the ContentProcessor attribute to specify the correct
/// display name for this processor.
/// </summary>
[ContentProcessor(DisplayName = "Livello Processor")]
public class LivelloProcessor : ContentProcessor<TInput, TOutput>
{
public override TOutput Process(TInput input, ContentProcessorContext context)
{
// TODO: process the input object, and return the modified data.
//Rilevo i valor degli elementi e il totale di ogni singolo elemento
string[] elementi = input.Split(new char[]{'\n'});
int righe = Convert.ToInt32(elementi[0]);
int colonne = Convert.ToInt32(elementi[1]);
int[,] dati = new int[righe, colonne];
//Eseguo un ciclo per rilevare i valori
for (int riga = 0; riga < righe; riga++)
{
string[] valori = elementi[riga + 2].Split(new char[] { ' ' });
//ciclo per le colonne
for (int Colonna = 0; Colonna < colonne; Colonna++)
{
dati[riga, Colonna] = Convert.ToInt32(valori[Colonna]);
}
}
//imposto la classe Livello, con i valori.
return new XNALivelloLibrary.Livello(dati);
}
}
}
Si crea un oggetto di tipo “Content Type Write” sempre per il progetto “XNALivelloContentPipelineExLib“.
Dalla finestra di “Esplora Soluzione” fate click destro sul nome del progetto, e selezioniamo la voce di menu, “nuovo elemento”. Nella finestra che viene visualizzata (figura 9) selezionate il modello relativo “Content Type Write” e nella casella nome, impostate il valore “LivelloTypeWrite”.
Figura 9
Nella parte di codice che viene generata, cambiamo il seguente frammento di codice
using TWrite = System.String;
In
using TWrite = XNALivelloLibrary.Livello;
Nel metodo Write, modificate il codice reimpostandolo con il seguente codice.
// TODO: write the specified value to the output ContentWriter.
output.Write(value.Righe);
output.Write(value.Colonne);
for (int riga = 0; riga < value.Righe; riga++)
{
for (int colonna = 0; colonna < value.Colonne; colonna++)
{
output.Write(value.OttieniValore(riga, colonna));
}
}
Mentre nel metodo GetRuntimeReader, impostiamo il nome della libreria, seguito dal metodo, qui di seguito l’esempio.
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
// TODO: change this to the name of your ContentTypeReader
// class which will be used to load this data.
return "XNALivelloLibrary.LivelloReader, XNALivelloLibrary";
}
Aggiungiamo una classe di tipo “Content Type Reader” , dalla finestra esplora soluzione, selezionare il progetto “XNAlivelloLibrary” e dal menu di scelta rapida, selezionare la voce, nuovo, e successivamente “nuovo elemento”.
Figura 10
Nella finestra che viene visualizzata (figura 10) selezionare il modello “Content Type Reader”, impostando nella casella Name, il valore “LivelloReader.cs”.
Modifichiamo la riga di codice
using TRead = System.String;
in
using TRead = XNALivelloLibrary.Livello;
Nel metodo read, scriviamo il codice che va a rilevare i vari dati.
protected override TRead Read(ContentReader input, TRead existingInstance)
{
// TODO: read a value from the input ContentReader.
int righe = input.ReadInt32();
int colonne = input.ReadInt32();
int[,] livello = new int[righe, colonne];
for (int riga = 0; riga < righe; riga++)
{
for (int Colonna = 0; Colonna < colonne; Colonna++)
{
livello[riga, Colonna] = input.ReadInt32();
}
}
return new Livello(livello);
}
Siamo giunti alla conclusione di questo tema, ora non ci resta che scrivere il codice nel progetto, quello relativo al games.
Tramite la finestra esplora soluzione, nel progetto XNALivello, dove si trova la classe game1, facciamo click con il tasto destro del mouse, e nel menu di scelta rapida,selezionate nuovo elemento, nella finestra che viene visualizzata selezioniamo il modello “Text File” o “File di testo”.
Figura 11
In questo modo verrà creato un file di testo.
Nella casella di testo “Name” o “nome” impostare il valore “Livello1.Livello”, questo sarà il nostro file di testo, con le informazioni dei livelli.
Confermate il tutto, tramite il pulsante “Add”.
Nel file, valorizziamo con i seguenti dati:
5
2
1 0
1 1
2 0
2 1
3 0
In questo modo viene indicato, che avremmo 5 righe e due colonne.
Livello1, quadro 0
Livello 1 quadro 1
Livello 2 quadro 0 e via continuando.
Copiamo questo file, nella sezione content ossia “XNALivelloContent”.
Nella finestra proprietà (figura 12) viene impostato automaticamente, i settaggi per i campi “Contert importer” e “Content Processor”,
Sempre nella sezione content, “XNALivelloContent” aggiungiamo un sprint font, in modo che possiamo gestire il testo da visualizzare a video.
Ora passiamo alla classe Game per caricare i dati di tale file.
Nella dichiarazione di variabile, scriviamo gli oggetti che ci permetteranno di gestire il file livello1, ed il testo da visualizzare a video.
Qui di seguito si riporta il codice di tali operazioni, i membri a livello di classe.
//oggetto di tipo livello
XNALivelloLibrary.Livello livello;
//gestione font
SpriteFont spriteFont;
//testo da visualizzare
string testo;
Nell’evento “LoadContent”, scriviamo il codice che inizializza l’oggetto livello, e l’oggetto relativo al carattere.
Qui di seguito si riporta tale codice dell'evento "LoadContent".
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//inizializzo l'oggetto livello
livello = Content.Load<XNALivelloLibrary.Livello>("Livello1");
for (int riga = 0; riga < livello.Righe; riga++)
{
for (int colonna = 0; colonna < livello.Colonne; colonna++)
{
if (colonna == 0)
testo += livello.OttieniValore(riga, colonna) + "\r\n";
else
testo += livello.OttieniValore(riga, colonna);
}
}
//imposto l'oggetto sprintFont con il contenuto
spriteFont = Content.Load<SpriteFont>("SpriteFont1");
// TODO: use this.Content to load your game content here
}
Nell’evento “Draw” si scrive il codice per la visualizzazione del testo a video.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
// Imposto il testo
spriteBatch.Begin();
spriteBatch.DrawString(spriteFont, testo, new Vector2(0, 0), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
Conclusioni
L'articolo ha voluto fornire al lettore la tecnica del content pipeline extension, per la gestione dei file, ed in particolare in quelle situazione in cu si devono gestire i livelli dei video giochi. Le varie immagini, chiariscono i numerosi passaggi che si devono compiere per utilizzare questa tecnica per la gestire i file.
Tramite la parola Download potete scaricare il file d'esempio di questo progetto.
Download