martes, 14 de julio de 2015

Ciclo de Vida en MonoGame

Cuando creamos un nuevo proyecto en MonoGame, la plantilla trae la clase Game1 con varios métodos. ¿Cuándo se ejecuta cada uno? ¿Para qué sirven? Lo primero es el ciclo de vida de una aplicación o juego en nuestro caso. Una imagen que encontré lo resumen bien claro.


Como en todas las aplicaciones de C#, por defecto, el programa arranca en el método Main de la clase Program. Allí dentro, en los proyectos de MonoGame, se instancia un objeto del tipo Game y se llama a su método Run. Internamente, el primer método que se llama es Initialize. En este método hay que escribir todo el código relacionado a inicializar objetos relacionados con el juego. Inmediatamente se llama al método LoadContent una única vez, donde se carga todo lo relacionado al contenido del juego, como sprites, fuentes, audio, etc. Luego viene lo que se denomina "Game Loop" que es la repetición hasta el fin de la invocación a los métodos Update y Draw (aunque a veces no secuencialmente, pero si muchas veces por segundo) repetidamente de acuerdo al "Frame rate" que se haya especificado al inicializar.  Update debe encargarse de tomar los inputs (teclado, gamepad, touchpad) del jugador y actualizar la física, la inteligencia artificial, el estado general del juego y las animaciones, aunque no de dibujarlas, solamente decidir el cuadro o frame que se debe mostrar.  Draw es quien debe dibujar y actualizar la pantalla con lo que se debe ver. Finalmente UnloadContent es llamado cuando el juego se termina y es el encargado de liberar los recursos usados en el juego.

Como verán, es bastante simple. En Initialize lo común es iniciar el nivel, el jugador y todo lo relacionado con el juego. En LoadContent lo que se hace es cargar los recursos, por ejemplo:

 protected override void LoadContent()  
 {  
     // Create a new SpriteBatch, which can be used to draw textures.  
     spriteBatch = new SpriteBatch(GraphicsDevice);  
     fuente = Content.Load<SpriteFont>("MiFuente");
     heroe = Content.Load<Texture2D>("heroe");
 }  

En UnloadContent, iría la liberación, pero generalmente no hay recursos que necesiten ser liberados explícitamente. El grueso de nuestro juego va a estar en Update, donde vamos tomando el input del jugador y actualizando el estado del juego. Y por último en Draw va todo lo que dibujamos. Es muy importante que todas las llamadas a spriteBatch.Draw() se hagan entre los métodos spriteBatch.Begin()spriteBatch.End(), pero no repitiendo estos últimos, sino que utilizándolos una única vez (o unas pocas en algunas excepciones) y llamando a spriteBatch.Draw() varias veces entre esos métodos. ¿Y por qué es esto? Habrán escuchado que las placas de video pueden dibujar millones de polígonos, pero si uno dibuja varias veces sin el cuidado anterior, la aplicación se ralentiza. El tema es que esos millones de polígonos deben venir todos juntos de una sola vez para optimizar el proceso y eso es lo que hace el Begin y End de spriteBatch, juntar todo lo que se dibuja y dibujar una sola vez.

martes, 7 de julio de 2015

Retomando

Hace tiempo que no escribo. Última publicación 22 de septiembre de 2012... puff. Bueno tengo un montón de excusas, pero mejor vamos a escribir código con el fin de crear videojuegos. En la publicación anterior mostré como hacer el "Hola Mundo" y como escribir en XNA. Bueno resulta que eso fue hace tanto que XNA ya está descontinuado. Lo nuevo y corriente es MonoGame. En el sitio oficial pueden ver toda la información, pero en resumidas cuentas, como XNA estaba muy bueno, este proyecto lo continua y además es Open Source, por las dudas que también caiga en algún momento. Lo novedoso es que es multi-plataforma.

Cuando empecé con MonoGame, otra vez me costo un poco lograr escribir algo por pantalla. Por eso, aquí les dejo los pasos que seguí para poder hacerlo:
  1. Si no tenés instalado MonoGame, lo primero obviamente es instalarlo. 
  2. Luego crear un nuevo proyecto. En mi caso fue un proyecto MonoGame para Windows. Aclaro que para los tutoriales estoy usando Visual Studio 2010, pero debería ser similar para versiones más nuevas. 
  3. Buscar la fuente que te guste e instalarla en tu SO. Buscando encontré un enlace con fuentes de Microsoft que se pueden usar libremente, pero finalmente me terminé quedando con Lucida Console que tiene todos los caracteres del mismo tamaño y me facilita otras tareas. En este punto hay que tener cuidado con los derechos de autor, porque por más que la fuente esté en tu PC, es posible que no esté permitido utilizarla con fines comerciales. En mi caso sólo la estoy utilizando para el ejemplo y en todo caso, académicamente y sin fines de lucro.
  4. En el proyecto creado, abrir el Content.mgcb. Este archivo es el que administra el contenido relacionado a sprites, fuentes, audio, etc. Anteriormente en XNA esto se hacia con un proyecto, pero esto quedó en el pasado.
  5. Una vez abierto el archivo, nos aperece la GUI del MonoGame Content Builder. Acá podemos agregar la fuente. Para ello hay que agregar  una "SpriteFont Description", o sea una descripción de una fuente. Es una descripción de la fuente a utilizar, porque la fuente está instalada.
  6. Una vez creado el archivo con el nombre que queremos, hay que editarlo con tu editor de texto o xml favorito. Lo que hay que cambiar fundamentalmente en el texto son los valores de los elementos <FontName> y <Size>. Allí ponemos el nombre de la fuente y el tamaño deseados (en mi caso Lucida Console, tamaño 12). Hay otros elementos pero creo que los más importantes son los que mencioné.
  7. Guardar y cerrar el archivo. Ahora con los cambios listos, hay que compilar el contenido (atajo F6). Todo debería estar Ok y podemos cerrar la GUI del contenido.
  8. Con la fuente cargada en el proyecto, resta instanciar un objeto SpriteFont en nuestro juego para cargarlar y usarla para escribir. Aquí se puede ver el código completo: http://codepaste.net/g83e1g.
En el código se puede ver los métodos básicos que se usan en el ciclo de vida de un juego en MonoGame. Esto me gustaría explicarlo en un próximo post para no alargar este.

Bueno, eso fue todo para la vuelta. He retomado el código para juegos (ahora con MonoGame) y el blog. Espero hacerlo con más frecuencia y que le sirva a alguien más.

Saludos!

sábado, 22 de septiembre de 2012

Escribir con XNA

En la publicación anterior, que denominé Hola Mundo, no hice referencia a como escribir el clásico cartel de "Hola Mundo" por pantalla. Cualquiera pensaría que es tan simple como hacer un print o similar, pero no es así. La verdad es que conlleva varios pasos. Tantos que tuve que buscar en Internet como hacerlo.


¿Pero tan difícil es? Bueno, no tanto, pero hay que hacer algunas cosas raras que no se hacen en otros programas para hacer un simple "Hola mundo". El tema es que para escribir con XNA, hay que "dibujar" un string con un método que pide especificar la fuente con un objeto SpriteFont. Y esta clase no trae miembros estáticos con valores comunes como la clase Color o Pens. Tampoco se puede hacer facilmente un new SpriteFont(). Para crear una fuente, se debe agregar un elemento nuevo al proyecto Content (el que está vacío y que se usar para los recursos del juego) con la plantilla Sprite Font. Ponemos el nombre que queramos y aparece un archivo xml donde se especifica las propiedades de la fuente. La más importante es "FontName" que dice qué fuente se va a importar. Esto quiere decir que se toma de las fuentes del sistema operativo, así que tenerlo muy presente cuando quieran usar fuentes instaladas a parte. La que viene (Segoe UI Mono) parece buena, pero siéntanse libres de cambiarla para ver como queda.

 <?xml version="1.0" encoding="utf-8"?>  
 <XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">  
  <Asset Type="Graphics:FontDescription">  
   <FontName>Segoe UI Mono</FontName>  
   <Size>14</Size>  
   <Spacing>0</Spacing>  
   <UseKerning>true</UseKerning>  
   <Style>Regular</Style>  
   <CharacterRegions>  
    <CharacterRegion>  
     <Start>&#32;</Start>  
     <End>&#126;</End>  
    </CharacterRegion>  
   </CharacterRegions>  
  </Asset>  
 </XnaContent>  

Una vez creado el elemento fuente en el proyecto de contenido, sólo resta crear una variable del tipo SpriteFont en nuestra clase principal (Game1 si no le cambiaste el nombre) y luego cargar la fuente en el método LoadContent:

 GraphicsDeviceManager graphics;  
 SpriteBatch spriteBatch;  
 SpriteFont fuente;

 protected override void LoadContent()  
 {  
     // Create a new SpriteBatch, which can be used to draw textures.  
     spriteBatch = new SpriteBatch(GraphicsDevice);  
     fuente = Content.Load<SpriteFont>("MiFuente");
 }  

Fíjense que no es necesario pedir memoria (asignar new) a "fuente" porque el objeto lo devuelve el método Load de Content, tal como sucederá con otros recursos como las imágenes.

Ahora si, vamos a escribir el famoso cartel. Para hacerlo, usaremos el método DrawString de nuestro SpriteBatch. Este método pide un objeto SpriteFont, el string a dibujar, la ubicación y el color. El primero es nuestro objeto "fuente" o como le hayan puesto ustedes. El string es "Hola Mundo". La ubicación es un objeto del tipo Vector2 que son muy similares a los Point, tienen un componente X y un componente Y. Podríamos hacerlo sencillo y poner new Vector2(20, 20), pero vamos a hacer algo más interesante y calcular el punto medio de la pantalla.

La parte que se dibuja en la ventana es representada con un objeto del tipo ViewPort. En nuestro juego se puede acceder mediante GraphicsDevice.Viewport. De aquí mismo podemos recuperar la altura y el ancho de la pantalla, pero vamos a acceder a TitleSafeArea que devuelve la zona segura para escribir. Y ahí si accedemos a Height y Width. Con esos valores armamos un objeto Vector2 y luego lo dividimos por 2 (Vector2.Divide). También se puede armar el vector con cada valor divido en 2.

¿Ya está? Casi. Si dibujamos en ese punto, el texto empezará en dicho punto, por lo que NO estará centrado en la pantalla. ¿Como escribir centrado en ese punto? Para ello tendremos que restarle al punto, la mitad del tamaño de la frase "Hola Mundo".


Para saber cuanto mide un string, se usa el método MeasureString que viene con el objeto SpriteFont. Eso devuelve un punto. Ese punto lo dividimos a la mitad y se lo restamos al punto medio calculado anteriormente. Y ahora si estamos en condiciones de dibujar el cartel en el medio de la pantalla. El color lo dejamos a gusto de cada uno.

         protected override void Draw(GameTime gameTime)  
         {  
             GraphicsDevice.Clear(Color.Black);  
             spriteBatch.Begin();  
             //  
             Vector2 pos = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.Width, GraphicsDevice.Viewport.TitleSafeArea.Height);  
             pos = Vector2.Divide(pos,2);  
             Vector2 tamaño = fuente.MeasureString("Hola Mundo");  
             pos -= Vector2.Divide(tamaño, 2);  
             spriteBatch.DrawString(fuente, "Hola Mundo", pos, Color.ForestGreen);  
             //  
             spriteBatch.End();  
             base.Draw(gameTime);  
         }  

Bien, eso fue todo. Esperando que el artículo lo hayan disfrutado tanto como yo al escribirlo, sólo resta dejar el link al código fuente y un saludo. Hasta la próxima entrega.

Descargar código fuente

sábado, 25 de febrero de 2012

Hola Mundo!




Y si, lo primero que hay que hacer con algo nuevo, el hola mundo.
Bueno en este blog voy a ir poniendo principalmente, mis experiencias con el desarrollo de juegos. También habrá otras noticias relacionadas con la informática en general.


Encontré un muy buen tutorial para hacer juegos con xna: Shooter
Es sencillo y trae todos los sprites y sonidos necesarios. Si bien el juego es simplón, sienta bases para mejores desarrollos y también por si quieres convertirlo en algo mejorado. El tutorial toma algo así como 90 minutos, incluyendo los videos. Está en inglés, espero que no desmotive.


Bien, esto fue todo por ahora. En las próximas entradas, más sobre xna y ese tutorial -¿traducción al español?- que la verdad estuvo muy entretenido. De hecho ya estoy trabajando en una remake del bomberman!!!