Publicado el 19/01/2013 por

XNA: SpriteFont, despliegue de texto

Saludos a todos. Hoy aprenderemos una nueva característica de XNA 4.0, los “SpriteFont”. Estos nos permitirán desplegar texto dinámicamente en nuestras escenas o proyecto de una manera fácil y cómoda. Estaremos estudiando que otras posibilidades de despliegue tenemos aparte de la configuración estándar.

Aquí les dejo algunos enlaces interesantes sobre XNA para que te inicies en él si aún no lo has hecho.

¿Qué es un SpriteFont?

Son un tipo de Asset que nos permitirá tener la configuración y estilo de un tipo de letra. En su estructura podemos configurar los parámetros básicos tales como el tamaño, estilo, separación, entre otros. Iniciemos un nuevo proyecto y veamos cómo trabajar con ellos.

Agregar un SpriteFont al proyecto

Es similar a agregar cualquier otro tipo de elemento a nuestro proyecto. Hacemos clic derecho sobre el contenedor y seleccionamos la opción “Agregar -> Nuevo elemento”

spriteFont

En el apartado XNA seleccionamos “SpriteFont” y le colocamos el nombre que queramos.

spriteFont
Nota

Te sugiero que le coloques el mismo nombre de la tipografía que usarás

¿Configuración de nuestro SpriteFont?

Al hacer doble click en el nuevo elemento agregado encontraremos las propiedades de este en formato XML


<?xml version="1.0" encoding="utf-8"?>

<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">

  <Asset Type="Graphics:FontDescription">

    <FontName>String Value</FontName>
    <Size>Float Value</Size>
    <Spacing>Float Value</Spacing>
    <UseKerning>true</UseKerning>
    <Style>String Value</Style>

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

</XnaContent>

Las principales propiedades son:

      • FontName: Nombre de la fuente a utilizar, Arial por ejemplo
      • Size: Tamaño de la funte en puntos. Es de tipo float
      • Spacing: Espacio entre carácter. Es de tipo float y esta unidad es a nivel de pixeles
      • Style: El estilo de la funte,regular, cursiva, etc.

Modificando cada propiedad ajustamos el SpriteFont al tipo y estilo de letra que necesitamos. Para ejemplificar su uso podemos usar esta configuración


	<FontName>Arial</FontName>
    <Size>18</Size>
    <Spacing>0</Spacing>
    <UseKerning>true</UseKerning>
    <Style>Regular</Style>

¿Cómo usar el SpriteFont?

      • Primero agregamos en nuestra clase (Game1 en este caso) una variable de tipo “SpriteFont”

	private SpriteFont _myArialFont;

      • Ahora en la función “Initialize” crearemos una instancia

	protected override void Initialize()
	{
	    _myArialFont = Content.Load<SpriteFont>("Arial");
	    base.Initialize();
	}

      • Ya tenemos nuestro tipo de texto preparado. Sólo resta el despliegue. Para ello hacemos uso del SpriteBatch en nuestra función Draw.

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

        spriteBatch.Begin();
        spriteBatch.DrawString(_myArialFont, "Mi primer texto", new Vector2(100,100), Color.White );
        spriteBatch.End();

        base.Draw(gameTime);
    }

Como ven usamos el spriteBatch para hacer nuestro despliegue. Los parámetros que recibe son muy simples: SpriteFont, Texto a mostrar, posición y color de texto.

      • y allí está nuestro texto.
spriteFont

Limitaciones

Lamentablemente no todo es perfecto. Los SpriteFont siendo usados como acabamos de ver tienen una limitación, solo trabaja con tipografías “True type” y “Open Type”. En cualquier otro caso debemos buscar alternativas para poder hacer el despliegue.

Ahora, ¿Qué hacer si por ejemplo deseamos usar la siguiente tipografía “Porscha 911”?

spriteFont

Lo que haremos es transformar nuestro tipo de letra en una imagen y usarla como un SpriteFont directamente, de esta forma no es necesario crear un SpriteFont y agregarlo a nuestro contenedor, ya que nuestra imagen o textura funcionará como tal.

Transformar tipografía a una imagen

Usaremos un proyecto desarrollados por las gente de Xbox live.

Ejecutamos el proyecto y nos aparecerá una pequeña ventana donde seleccionaremos nuestra tipografía, configuramos su tamaño y la exportamos en formato “.Bmp”

spriteFont
Nota

Como mensioné, yo usaré la tipografia “911 Porscha” y la exportaré con un tamaño de 48 pixeles

Luego del proceso de exportación el resultado es el siguiente

spriteFont

Ahora agregamos esta textura a nuestro proyecto

spriteFont

El siguiente paso es de suma importancia, porque si lo omitimos nada de lo que hagamos funcionará, de hecho nos generará errores de ejecución. Debemos seleccionar la textura de la fuente y en sus propiedades cambiar el tipo de procesador a utilizar, de “Texture” a “Sprite Font Texture”.

spriteFont

A partir de este punto todo se mantiene igual en un 90%, sin embargo, hay una consideración importante: La escala.

En el primer método la escala es calculada de manera automática, pero ahora tenemos que encargarnos nosotros. Para poder tener un tipo de letra totalmente funcional y que en futuros usos no nos genere trabajo adicional tratando de recordar el tamaño en que fue exportada la letra, cuál es la escala a utilizar, entre otras, desarrollaremos una clase especialmente para usar nuestra letra personalizada y así manejar el problema de la escala.

Clase PorschaFont

Aquí crearemos una estructura que le dará soporte a todas las características de nuestra letra. Agregamos una clase a nuestro proyecto y la nombramos “PorscheFont”, la estructura base a utilizar dentro de nuestra clase será esta.

spriteFont
      • Region Members: Constantes y variables privadas

	//Escala normalizada del texto Badaboom
	private const float NormalizeScale = 1f/48f;

	//Proporción de anchura con respecto a la altura del texto
	private const float WidthScaleProportion = 0.81f;

	//spritefont para el despliegue del texto Badaboom
	private readonly SpriteFont _font;

De todas las variables hay una en particular de vital importancia y que debemos tomarnos un tiempo para calcular su valor “WidthScaleProportion ”. Esta variable representa la proporción entre la altura y anchura de nuestro texto, es decir, dada una altura qué porcentaje de esta debe ser la anchura. Esto lo hacemos para mantener la proporción correcta de nuestro texto, ya que si en el parámetro escala colocamos cualquier valor podemos obtener resultados no deseados “un texto super ancho y enano por ejemplo”

Para calcular este valor lo que haremos es determinar cuánto es el alto y el ancho de un carácter promedio. el procedimiento gráficamente.

spriteFont
Nota

La imagen del caracter (en mi caso la letra d) debe ser tomada de la imagen exportada.

      • Region Properties: Propiedades de nuestra texto que podemos manipular externamente

	//Escala base de nuestro texto
    public Vector2 Scale;

    //Color para el render de nuestro texto
    public Color FontColor;

      • Region Constructors: Inicializador de nuestra clase

	/// <summary>
    /// The base Constructor.
    /// </summary>
    public PorschaFont(ContentManager content, float heightScale)
    {
        _font = content.Load<SpriteFont>("porscha");
        Scale = new Vector2(heightScale * WidthScaleProportion, heightScale);
        FontColor = Color.White;
    }

Aquí iniciamos nuestro SpriteFont cargando la textura directamente como un tipo de fuente, y calculamos la escala horizontal basada en nuestro número mágico “WidthScaleProportion” y la altura deseada en pixeles.

      • Region Extra: Funcion de despliegue

	public void Draw(SpriteBatch spriteBatch, String text, Vector2 position, bool centerText = false )
    {
        var origin = (centerText) ? _font.MeasureString(text) * 0.5f : Vector2.Zero;

        spriteBatch.Begin();
        spriteBatch.DrawString(_font, text, position, FontColor, 0f, origin, Scale * NormalizeScale, SpriteEffects.None, 0);
        spriteBatch.End();
    }

Con esta función podremos desplegar nuestro texto en pantalla. Internamente hay dos valores que vale la pena discutirlos.

    • Origin: Centramos el texto si así lo deseamos, calculando el ancho de nuestro texto. La lógica detrás de este valor es que el texto será desplazado “origen” unidades a la izquierda a partir de la posición indicada al momento del despliegue.
    • Scale * NormalizeScale: Representa el tamaño de nuestro texto en la escala correcta. Este valor podría tenerse calculado previamente si así lo desean.

Ya tenemos nuestra clase lista para usarse. Lo que haremos es tener una instancia de ella en nuestra clase principal e invocar el método draw donde se necesite.


	private PorschaFont _porschaFont;

	//...
	_porschaFont = new PorschaFont(Content, GraphicsDevice.Viewport.Bounds.Height * 0.05f );

	//...
	_porschaFont.Draw(spriteBatch, "Mi segundo texto", new Vector2(100, 200), true);

spriteFont

Conclusión

Hemos avanzado bastante hoy en relación al despliegue de texto en XNA. Ya podemos usar prácticamente cualquier tipo de texto en nuestro proyecto. Adicionalmente tenemos una estructura creada que nos permitirá agregar más tipografías y gestionarla de una manera eficiente. Espero hayan aprendido cosas nuevas con este tutorial, y no olviden dejar sus comentarios y preguntas, y seguirnos por nuestras redes sociales.

En próximas entregas les enseñaré como desplegar textos con borde o con degradados en sus proyectos como este

spriteFont

Etiquetas: , , , , , , ,

Sobre el formador:
Luiyit Hernández

Es estudiante de la Universidad Central de Venezuela desde el año 2008 y actualmente en el noveno semestre de licenciatura en Computación. Dedicado al área de diseño y desarrollo web, diseño gráfico y computación gráfica. Seguidor fiel del FC Barcelona y Rafael Nadal. Hobbies: pensar, música, cine, video juegos y baile. Cuidadoso en los detalles y apasionado en lo que hace.


  • ghjtyu

    Hola, por favor hagan enfasis en los tutoriales de OpenGL que hacen falta en la web, es decir hay otro pero no estan tan bien explicados y XNA ya esta muy documentado por el soporte que da Microsoft.

    • http://widget-pc.com/ Luiyit Hernández

      Gracias por comentar. Gracias por tu sugerencia, realmente la apreciamos mucho.
      Saludos!