Introduzione
In questo articolo, vedremo come creare un semplice gioco o meglio una semplice applicazione in XNA per la gestione delle lingue, ossia regioni diverse.
I videogames, a volte, possono avere lingue internazionali, l'articolo fornisce al lettore le conoscenze per rendere la propria applicazione multi lingua.
Creazione del progetto
Dopo aver creato un nuovo progetto, si aggiunge (tasto destro sulla soluzione in Esplora soluzioni) un progetto di tipo "Content Pipeline Extension Library", il tutto come mostrato in figura 1.
Figura 1
Nel progetto appena creato, si aggiunge una nuova classe di nome "RegioneFontDescrizione" in questo modo possiamo gestire il carattere (figura 2)
Aggiungiamo lo spazio dei nome "Microsoft.Xna.Framework.Content.Pipeline.Graphics" per gestire la classe del carattere, mentre lo spazio dei nomi "Microsoft.Xna.Framework.Content" per gestire alcuni aspetti della proprietà.
La classe deve ereditare da "FontDescription".
Il tutto come mostrato qui di seguito.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//spazio di nomi per la gestione del testo
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content;
namespace ContentPipelineExLocalizzato
{
class RegioneFontDescrizione : FontDescription
{
}
}
Si crea una proprietà che avrà il compito di gestire i file di risorse.
Qui di seguito il frammento di codice per tale proprietà
List<string> m_fileRisorsa = new List<string>();
//proprietà per la gestione dei file Risorse
[ContentSerializer(Optional = true, CollectionItemName = "Resx")]
public List<string> FileDiRisorse
{
get { return m_fileRisorsa; }
}
Riportiamo il codice completo di questa classe.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//spazio di nomi per la gestione del testo
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content;
namespace ContentPipelineExLocalizzato
{
class RegioneFontDescrizione : FontDescription
{
//costruttore
public RegioneFontDescrizione()
: base("Arial", 14, 0)
{
}
List<string> m_fileRisorsa = new List<string>();
//proprietà per la gestione dei file Risorse
[ContentSerializer(Optional = true, CollectionItemName = "Resx")]
public List<string> FileDiRisorse
{
get { return m_fileRisorsa; }
}
}
}
Ora dobbiamo creare una classe per gestire il carattere, dopo aver creato una classe (tasto destro sul nome del progetto, nuova classe) figura 3 impostiamolo che erediti da "ContentProcessor"
Figura 3
La nuova classe deriva dalla classe contentProcessor che accetta due argomenti, la classe precedente, quella relativa alla gestione della descrizione del carattere e la gestione del carattere font per la visualizzazione.
Aggiungiamo lo spazio dei nomi per gestire il content.
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
class RegioneFontProcessor : ContentProcessor<RegioneFontDescrizione, SpriteFontContent>
{
}
La classe avrà lo scopo di gestire i vari file di risorse.
Dobbiamo effettuare l'ovverride del metodo SprintFontContentProcess, gestendo il file risorse come un file xml.
Qui di seguito si riporta il codice completo della classe RegioneFontProcessor.
//spazio dei nomi
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using System.IO;
using System.Xml;
namespace ContentPipelineExLocalizzato
{
class RegioneFontProcessor : ContentProcessor<RegioneFontDescrizione, SpriteFontContent>
{
//faccio un ovverid del metodo process per gestire le informazioni
public override SpriteFontContent Process(RegioneFontDescrizione inputFont, ContentProcessorContext contextProces)
{
//verifico tutti i file di risorse per le vari voci
foreach (string resourceFile in inputFont.FileDiRisorse)
{
string percorso = Path.GetFullPath(resourceFile);
//se il file non esiste, genero un eccezione
if (!File.Exists(percorso))
{
throw new InvalidContentException("File non presente " + percorso);
}
//carico in un oggetto di tipo xml i dati del file risorse
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(percorso);
//esamino le varie chiavi e inserisco il valore del carattere trovato nella classe per la gestione del carattere
foreach (XmlNode xmlNode in xmlDocument.SelectNodes("root/data/value"))
{
string ValotreTrovato = xmlNode.InnerText;
//aggiungo alla classe di descrizione del carattere il valore trovato
foreach (char usedCharacter in ValotreTrovato)
{
inputFont.Characters.Add(usedCharacter);
}
}
//rigenero ogni volta il dato, quando viene modificato il file di risorsa
contextProces.AddDependency(percorso);
//generazione del tipo di carattere
}
return contextProces.Convert<RegioneFontDescrizione,
SpriteFontContent>(inputFont, "RegioneFontProcessor");
}
}
}
Terminata la creazione della classe, non ci resta che aggiungere nella sezione content, del progetto XNA, un oggetto di tipo SprintFont.
Nella sezione "Content" facciamo click con il tasto destro, selezioniamo dal menu di scelta rapida, aggiungi e successivamento elemento, selezioniamo tra i vari modelli quello relativo a sprintfont
Figura 4
Nel campo Name, lasciamo il nome così com’è.
Nel file sprintefont, modifichiamo
<Asset Type="Graphics:FontDescription">
in
<Asset Type="ContentPipelineExLocalizzato.RegioneFontDescrizione">
Dove il primo indica il nome del progetto, mentre il secondo è la descrizione..
Aggiungiamo un tag al file, il quale indica i nomi dei file di risorse, qui di seguit si riporta il frammento di codice.
<FileDiRisorse>
<Resx>..\Testo.resx</Resx>
<Resx>..\Testo.En.resx</Resx>
</FileDiRisorse>
Nella sezione "Content" aggiungiamo il riferimento al progetto "ContentPipelineExtension" creato precedentemente, il tutto come mostrato in figura 5.
Figura 5
Visualizzare le varie culture
Passiamo alla classe per la gestione del videgioco, in modo che scriviamo le varie funzioni per gestire il settaggio. Nella classe Game1, dichiariamo degli oggetti a livello di classe, il tutto come mostrato qui di seguito.
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont font;
Nel caso che abbiamo il pc con la regione italiana, utilizziamo currentCulture, altrimenti tramite la parola chiave new, inizializziamo la proprietà culture con CultureInfo di tipo inglese.
//oggetto risorsa
Testo.Culture = CultureInfo.CurrentCulture;// new CultureInfo("en-US");
Nell’evento loadcontent inizializziamo il carattere, con il font appena aggiunto nel contento. Riportiamo il frammento di codice per l'evento LoadContent.
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//Carico il caraterre
font = Content.Load<SpriteFont>("SpriteFont1");
// TODO: use this.Content to load your game content here
}
Nell’evento Draw, visualizziamo a video le varie impostazoni. Qui di seguito si riporta il codice completo dell'evento Draw.
protected override void Draw(GameTime gameTime)
{
string TestoSaluto = Testo.benvenuto;
string TestoLivello = Testo.Livello;
string TestoFineGioco = Testo.FineGioco;
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(font, TestoSaluto, new Vector2(100, 100), Color.White);
spriteBatch.DrawString(font, TestoLivello, new Vector2(100, 150), Color.White);
spriteBatch.DrawString(font, TestoFineGioco, new Vector2(100, 200), Color.White);
spriteBatch.End ();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
La stesura del codice è completata, 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;
using System.Globalization;
using System.Collections;
namespace XNALocalizzato
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont font;
public Game1()
{
Content.RootDirectory = "Content";
graphics = new GraphicsDeviceManager(this);
//oggetto risorsa
Testo.Culture = CultureInfo.CurrentCulture;// new CultureInfo("en-US");
}
/// <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
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);
//Carico il caraterre
font = Content.Load<SpriteFont>("SpriteFont1");
// 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();
KeyboardState currentKeyboardState = Keyboard.GetState();
if (currentKeyboardState.IsKeyDown(Keys.Escape) )
{
Exit();
}
// TODO: Add your update logic here
base.Update(gameTime);
}
/// <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)
{
string TestoSaluto = Testo.benvenuto;
string TestoLivello = Testo.Livello;
string TestoFineGioco = Testo.FineGioco;
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(font, TestoSaluto, new Vector2(100, 100), Color.White);
spriteBatch.DrawString(font, TestoLivello, new Vector2(100, 150), Color.White);
spriteBatch.DrawString(font, TestoFineGioco, new Vector2(100, 200), Color.White);
spriteBatch.End ();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
}
Conclusioni
La localizzazione nei video giochi è molto considerata, visto che ad oggi i vari produttori di videogiochi, esportano il proprio video gioco in diversi paesi. Rendere il proprio gioco multi lingua, permetterebbe di ampliare il numero dei giocatori.