kalabaza.com.mx
Sitio de animación y desarrollo de video juegos

Fantasma

En vista de que he hecho varias modificaciones a las imágenes con las que hemos estado trabajando y dado que hay varias cosas importantes que hay que considerar al momento de crear los sprites, he decidido agregar este post en donde explico el proceso que seguí para crear los sprites de Megaman. Cabe señalar el post no pretende ser una guía paso a paso ya que el proceso es muy repetitivo, más bien esta hecho así a manera de explicar el razonamiento que hay que hacer para obtener los sprites como queremos. Una vez que leas este post ya podrás modificar tus sprites como quieras y ya sabrás las cosas que hay que tomar en cuenta.

 

Primero que nada empecemos abriendo la imagen original que agregué en el post “Carga y animación de un sprite” y que como comenté la descargué de Sprites-resources.com.

 

 

megaman sprites

 

 



Nota: para la edición de imágenes generalmete utilizo  Gimp que, para los que no lo conocen, es un editor de imágenes open source muy bueno que les recomiendo utilizar. Sin embargo para este ejemplo yo voy a utilizar Photoshop CS3 porque me parece que es más claro lo que quiero mostrar aquí.

 

Lo que voy a hacer ya que esta la imagen abierta es seleccionar uno de las sprites que utilizamos en la secuencia de avance. Este sprite lo voy a pegar en una imagen nueva y para fines del ejemplo le voy a poner un fondo blanco.

 

 

Sprite_Edit1

 

 

En un principio yo trataba que hacer la imagen lo mas pequeña posible reduciendo el area del fondo, sin embargo, si abrimos el tercer sprite de la animación (el que ocupa más espacio) y comparamos estos dos, podremos ver que hay una diferencia grande de dimensiones.

 

 

Sprite_Edit2

 

 

El problema no es que sea más grande sino que como recordarán, al insertar una imagen en pantalla se utilizan el origen de la misma (la esquina superior izquierda) para posicionarlo. Si para todas las imágenes utilizamos el criterio del menor área y generamos la animación así, obtendremos lo siguiente:

 

 

MegaMan1

 

 

Como pueden observar, la animación queda muy rara y tomando como referencia la cabeza de Megaman podemos ver como avanza y regresa. ¿Que podemos hacer entonces? lo que se necesita es tomar de referencia, como ya dije, la cabeza de Megaman ya que aunque en la animación este girando no debe desplazarse si todo el cuerpo no se desplaza. Para hacer esto necesitamos ubicar la cabeza de a la misma distancia en todas las imágenes y es aqui donde vamos a usar una opción de Photoshop, que aunque esto no es un tutorial de como usar photoshop les paso las rutas de las opciones que seleccioné.

 

Primero voy a tomar de referencia las mismas dos imágenes que puse más arriba y lo que voy a hacer es mostrar el grid en ellas para ver cada pixel de la imagen. Para esto en el menú seleccionamos View/Show y seleccionamos Grid como se muestra en la imagen:

 

 

Menu1

 

 

Al hacer esto nos va a mostrar una cuadrícula sobre la imagen y lo que vamos a hacer ahora es modificar esta cuadricula para que sea tan lo más pequeña posible y para hacer esto entramos al menú PhotoShop/Preferences/Guides,Grid,Slices & Cont… como se muestra en la figura.

 

 

Menu2

 

 

Nota: Como pueden ver estoy usando la versión de Mac en inglés pero espero que no tengan muchos problemas si ocupan una versión diferente.

 

Ya que se haya desplegado la ventana de opciones, vamos a cambiar la parte de Grid para que quede como la figura:

 

 

Menu3

 

 

Con esto ya podemos ver cada píxel de la imagen, aún en la parte blanca y lo que vamos a hacer ahora modificar cada imagen de tal forma que la cabeza de Megaman empiece en el mismo píxel para todas como en la siguiente imagen.

 

 

Sprite_Edit3

 

 

Si hacemos esto ya no debería haber ningún problema; La animación debe haberse corregido y debe verse como en la siguiente imagen.

 

 

MegaMan2

 

 

Sin embargo todavía hay un problema ya que nosotros estamos ocupando los mismos sprites para la animación de desplazamiento a la derecha como a la izquierda y al invertirlos tendremos el mismo problema que al principio, por lo tanto tendremos que aplicar el mismo procedimiento que antes y contar el número de pixeles que hay del lado derecho para que sea el mismo para todas las imágenes, como se muestra en la imagen.

 

 

Sprite_Edit4

 

 

Con esto solo restaría borrar el fondo blanco que ocupé para ver el Grid y listo ya tendríamos los sprites para la animación.

 

Como siempre, gracias por leer este post, espero que haya sido de su agrado y utilidad. Nos vemos en el siguiente post.

 

Piroshi

 


Tags:

Listas

 

 

Las listas son clases (contenidas en System.Collections.Generic) diseñadas especialmente para agrupar objetos y con esto realizar tareas que de otra forma implicarían muco código. La sintaxis general de una lista es la siguiente:

 

          List<type> name = new List<type>();

 

donde:

 

   type: es el tipo de objetos que vamos a agrupar
   name: es el nombre que le vamos a dar a nuestra lista

 

por ejemplo para crear una lista de strings podemos escribirla de la siguiente forma:

 

          List<string> ListaSaludos = new List<string>();

 

una de las ventajas de las listas que no necesitasmos definir el tamaño de la misma y puede aumentar o reducir el número de los elementos que lo componen. Los métodos principales de las listas son los siguientes:

 

Add() : Este método nos sirve para agregar elementos nuevos a nuestra lista. Estos
elementos se van agregando al final de la misma y automáticamente aumenta la dimensión de la lista agregando un nuevo indice. A continuación les muestro uno ejemplos.

 

         ListaSaludos.Add(“Hola”);
         ListaSaludos.Add(“Adios”);
         ListaSaludos.Add(“Buenos días”);

 

Remove() : Como su nombre lo indica, este método se utiliza para remover elementos de la lista. Para especificar el elemento a remover hay que escribri el valor del mismo, sin embargo, cabe señalar que las listas pueden tener elemmentos repetidos, así que si se aplica este método se removerá el
primer elemeto que encuentre con ese valor.
Para ver la sintaxis les muestro un par de ejemplos:

 

          ListaSaludos.Remove(“Adios”);

 

Insert(): Como comenté antes, el método Add()agrega elementos al final de la lista pero si queremos agregar un elemento en un indice especifico usamos el método Insert() de la siguiente manera:

 

          ListaSaludos.Insert(1,”Ciao”);

 

Sort(): Este método nos sirve para ordenar los elementos dentro de la lista.

 

          ListaSaludos.Sort();

 

Clear(): Este método nos sirve para borrar todos los elementos de una lista y su
sintaxis es la siguiente:

 

          ListaSaludos.Clear();

 


Acceder a los elementos de una lísta

 

Al igual que con los arreglos, para acceder a un elemento dentro de una lista utilizamos su indice correspondiente. cabe señalar que también al igual que con los arreglos, el primer elemento de una lista tiene el
indice uno. Por ejemplo si quieresmo acceder al tercer elemento de nuestra lista tendríamos que escribir lo siguiente:

 

          String1 = ListaSaludos[2];

 

donde String1 sería un objeto del tipo String que recibirá el valor de nuestra lista que para nuestro ejemplo sería el string “Buenos días”.


Tags:

XNA

 

 

Bienvenidos a este nuevo Post. La vez anterior pudimos desplegar sprites en pantalla y hacer una animación con ellos. Lo que vamos a hacer ahora es utilizar las teclas de dirección del teclado para poder controlar a nuestro personaje. Antes de empezar puedes consultar el post “Edición básico de sprites” si quieres saber el proceso que seguí para generar los sprites.

 

Los puntos que vamos a ver en este post son los siguientes:

 

 

    * Mejora del código anterior.
    * Carga de imagen adicional.
    * Modificación del método Draw()
    * Entrada de datos desde el teclado.
    * Creación de constructores
    * Carga de una imagen de Fondo.

 

 

Modificación del código anterior

 

Lo primero que vamos a hacer , como comenté al final del Post anterior es darle una arregladita al código para hacerlo más compacto. Lo primero será abrir nuestro proyecto del Post anterior y abrir el archivo AnimSprite.cs. Aquí lo que vamos a hacer es cambiar el nivel de acceso de nuestro arreglo SpriteMove a private para que solo la misma clase tenga acceso a él. Además, ya no va a ser un arreglo, si no una lista por dos razones, la primera es por que reduce bastante el código y se vuelve muy sencillo de entender y la segunda es para empezar a utilizar una forma de agrupar objetos diferente a los arreglos.  Para conocer más sobre las listas agregué un post que puedes consultat llamado “Listas” debajo de “Consideraciones del C#” por si la sintaxis no es muy clara y quieres conocer mejor su uso. Con estos cambios la declaración quedaría así:

 

     privateList<Texture2D> SpriteMov = newList< Texture2D>(); 

 

Ya que modificamos nuestro objeto lo siguiente es crear un nuevo método que se llamará  CargaImagen() el cual tendrá el siguiente código:

 

        public voidCargaImagen(Texture2D Sprite)
        {
           SpriteMov.Add(Sprite);
        }

 

Es un código muy simple que lo único que hace es recibir un sprite de tipo Texture2D y cargalo a nuestra lista que acabamos de crear; Como comenté antes, utilizando listas el código se vuelve muy simple pues lo único que hace falta es utilizar el Método Add() de la lista para agregar un nuevo elemento. Por otro lado lo que vamos a hacer es abrir nuestra clase Engine.cs para modificar el código que ocupábamos para cargar las imágenes dentro de método LoadContent(), el cual va a quedar así:

 

             for (int i = 1; i<=6; i++)
             {
               Megaman.CargaImagen(Content.Load<Texture2D>(”Sprites/MM”+ i));
             }

 

Lo que hace este código es iterar seis veces (que es el número de imágenes que forman la animación) y aprovechando que las imágenes comparten el nombre común “MM” más un número. Podemos incrementar ese número en un ciclo y concatenarlo al final del nombre genérico para obtener el nombre de cada imagen a cargar. El resultado del Load lo pasamos a la función CargaImagen() que acabamos de hacer y listo ya tenemos un código mas eficiente para la carga de imágenes.

 

 

Carga de Imagen adicional

 

Antes de seguir adelante voy a explicar lo que vamos a hacer. Actualmente tenemos a nuestro Megaman corriendo sin parar en un fondo blanco y lo que queremos, obviamente, es tener el control del personaje y sus movimientos, por lo pronto y para este post nos limitaremos a desplazar al personaje hacia la izquierda y hacia la derecha utilizando las flechas de dirección del teclado. Para lograr esto hay algunas consideraciones a tomar.

 

Primero, los sprites que tenemos ahora son de una animación continua y es por eso que es necesario carga una imagen más para nuestro personaje de pie y sin avanzar.

 

Segundo, actualmente tenemos seis sprites para el movimiento de Megaman hacia la derecha y agregaríamos un nuevo sprite con lo que ya tendríamos siete, pero si queremos que el personaje se desplace también hacia la zquieda harán falta otros siete sprites de Megaman corriendo hacia la izquierda más uno de pie mirando también hacia la izquierda. Si abrimos nuestras imagines en un editor de imágenes, las volteamos y guardamos con un numero consecutivo tendríamos todas nuestros sprites, sin embargo para hacerlo de una manera más elegante vamos a ocupar los mismos sprites que tenemos y por código vamos a invertirlos hacia la izquierda si la animación es en esa dirección.

 

Para cargar la imagen seguiremos el proceso visto en el post anterior “Carga y animación sprites” y la imagen a cargar es la siguiente:.

 

MM7

 

 

Modificación del método Draw()

 

Ya que tenemos siente sprites cargadas en nuestro programa necesitamos modificar el ciclo for que acabamos de escribir para agregar una imagen más

 

 

             for (int i = 1; i<=7; i++)
             {
               Megaman.CargaImagen(Content.Load<Texture2D>(”Sprites/MM”+ i));
             }

 

Por otro lado para lograr voltear la imagen necesitamos hacer varias modificaciones. Primero vamos a cambiar el método Draw() de nuestra clase AnimSprite.cs ya que anteriormente solo llamábamos al metodo Draw() del spriteBatch,  con el vector de posición y un color de mascara pero para voltear la imagen tenemos que llamar a otra versión sobrecargada del mismo método Draw() que utiliza otros parámetros. Lo primero que necesitamos es declarar una nueva variable dentro de nuestra clase AnimSprite.cs de tipo entero que llamaremos UltimaDir.

 

      public int UltimaDir;

 

Esta variable la vamos a utilizar de la siguiente manera: si se presionó la tecla de dirección derecha le asignaremos el valor de 0 y si fue presionada la tecla de dirección izquierda la asignaremos el valor de 1. (abajo viene la explicación de como cachar estos eventos). Utilizando esta variable nuestro método Draw() quedaría así:

 

       public void Draw(SpriteBatch spriteBatch)
        {
           spriteBatch.Begin();

             if(UltimaDir== 0)  //Derecha
                 spriteBatch.Draw(SpriteMov[FrameActual], new Rectangle(XPos, YPos,
                  SpriteMov[FrameActual].Width,SpriteMov[FrameActual].Height), null,Color.White,
                  Angulo,Origen, SpriteEffects.None,0f);

             else if(UltimaDir== 1)  //Izquiera

                 spriteBatch.Draw(SpriteMov[FrameActual], newRectangle(XPos, YPos,

                 SpriteMov[FrameActual].Width, SpriteMov[FrameActual].Height), null, Color.White,
                 Angulo, Origen, SpriteEffects.FlipHorizontally,0f);

           spriteBatch.End();
       }

 

 

Lo que hacemos es dividir el código en dos opciones, la primera es cuando la última tecla de dirección presionada fue la derecha  (UltimaDir ==0) y la segunda es cuando la última tecla de dirección fue la izquierda (UltimaDir ==1). Para el primer caso vamos a mostrar los sprites en su forma normal, sin embargo para mostrar congruencia en los dos casos he llamado al mismo método sobrecargado de Draw() al que le vamos a pasar los siguiente parámetros:

 

Primero: new Rectangle(XPos, YPos, SpriteMov[FrameActual].Width,
SpriteMov[FrameActual].Height)
, En lugar de ocupar el vector de posición que ocupábamos en el post pasado esta sobrecarga utiliza un objeto Rectangle que lo que va hacer es colocar nuestro sprite dentro de un rectángulo definido por cuatro puntos que corresponden a la esquina superior izquierda, el largo y el ancho del mismo, de tal forma que si definimos un rectángulo de diferentes dimensiones que nuestro sprite este se acoplará a las dimensiones del mismo pero como para nuestro caso queremos mantener las dimensiones originales, vamos a hacer lo siguiente: En lugar de nuestro vector de posición vamos a declarar un par de variables enteras que nos servirán para definir la posición de nuestro personaje 

 

       public int XPos, YPos;  

 

A continuación para definir las dimensiones del rectángulo vamos a utilizar las dimensiones del sprite para garantizar que mantendrá su forma al momento de dibujarlo en pantalla. Para eso es que se utilizan los parámetros Width y Height de nuestro sprite a dibujar

 

Segundo: null. El segundo parámetro es un objeto también del tipo Rectangle que se utiliza cuando se quiere dibujar solo una porción del sprite. Esta porción será la que contenga el rectángulo que definamos, pero para nuestro caso, enviamos un valor nulo para indicar que dibujaremos el sprite completo.

 

Tercero: Color.White  El color de mascara que es el mismo que en la sobrecarga anterior y que seguirá siendo blanca osea sin mascara.

 

Cuarto: Angulo  Este parámetro es el ángulo de rotación de nuestro sprite, en caso de que quisiéramos rotarlo ; Para este parámetro vamos a tener que declarar una nueva variable donde almacenaremos  un ángulo de rotación para cuando haga falta.

 

        public float Angulo;

 

Quinto Origen ,  Al definir la rotación de un objeto es necesario definir el pivote u origen con respecto al cual se va a efectuar esta rotación, es por eso que vamos a declarar un vector que almacene ese origen de rotación y se lo vamos a pasar como parámetro.

 

        public Vector2 Origen;

 

Sexto: SpriteEffects.None Y finalmenta la razón por la cual utilizamos esta sobrecarga: el efecto, que para el caso del avance hacia la derecha es None (porque permanecerá sin cambios) pero para cuando avanza a la izquierda será FlipHorizontally. Y que es esto? Pues este parámetro nos indica si el sprite será dibujado sin alteración (SpriteEffects.None) o volteado sobre el eje  horizontal (SpriteEffects.FlipHorizontally).

 

Septimo : 0f . Este parámetro es un número flotante que indica la profundidad del sprite dentro de la pantalla, esto se utiliza cuando tenemos varios sprites en pantalla para definir cual va arriba de cual. Para nuestro caso mandamos 0 para poner el personaje más enfrente en caso de que hubiera otros sprites.

 

 

Entrada de datos desde el teclado

 

Para cachar la entrada de datos desde el teclado vamos a escribir la siguiente línea dentro nuestro método Update() y dentro de nuestra if que controla el tiempo

 

      KeyboardStatekState= Keyboard.GetState();

 

Lo que estamos haciendo aquí  es declarar un objeto que llamaremos  kState de la clase KeyboarState.

 

Esta clase ya nos hace toda la chamba para la verificación del estado de las teclas ya que al llamar al método GetSatate() podremos preguntar si una tecla fue presionada o no. Lo que necesitamos ahora es checar el estado de las teclas que nos interesan, que son las teclas de dirección izquierda y derecha pero que hacemos después? Por ejemplo, si presionamos la tecla de dirección derecha lo que queremos es que Megaman se desplace hacia la derecha pero también que la animación empiece a correr y nos muestre un frame tras otro y que al terminar los seis, vuelva con el primero como hicimos en el ejemplo anterior, además queremos que al dejar de presionar la tecla izquierda se detenga el desplazamiento, la animación y que se despliegue el sprite de Megaman parado y viendo hacia la derecha. Para hacer esto necesitamos saber si la tecla de dirección izquierda esta presionada en el momento de la verificación pero también necesitamos saber si fue presionada antes o mejor dicho si no ha dejado de ser presionada. Para verificar esto necesitamos almacenar en una variable el estado anterior de la tecla al momento de hacer una nueva verificación y para hacer eso vamos a utilizar la variable UltimaDir que declaramos antes. Utilizando esta variable podemos cambiar el código que utilizábamos para modificar la animación de Megman por el siguiente código dentro del método Update() de la clase Engine.cs

 


       if (kState.IsKeyDown(Keys.Right) && kState.IsKeyUp(Keys.Left))
          {
               Megaman.XPos +=10;
                  if (Megaman.UltimaDir == 0)
                      Megaman.UpdateMov();    
              Megaman.UltimaDir = 0;
          }
       else if (kState.IsKeyDown(Keys.Left) && kState.IsKeyUp(Keys.Right))
          {
               Megaman.XPos -= 10;
                  if (Megaman.UltimaDir == 1)
                      Megaman.UpdateMov();
               Megaman.UltimaDir = 1;
          }
        else
          {
                 Megaman.FrameActual = 6;
          }

 

Lo que hacemos aquí es utilizar nuestro objeto kState que acabamos de instanciar y vamos a utilizar el método isKeyDown() que recibe como parámetro la tecla a evaluar a través de un objeto Keys. Lo que preguntamos en el primer if es si la tecla de dirección derecha fue presionada (IsKeyDown) pero la tecla de dirección Izquierdo no fue presionada (IsKeyUp) Si se cumple esta condición entonces desplazaremos a nuestro personaje diez pixeles a la derecha. Además si no se a soltado la tecla de dirección derecha (UltimaDir == 0) pasaremos al siguiente frame de nuestra animación.

 

Por último guardamos en nuestra variable UtimaDir que la tecla de dirección derecha fue presionada.

 

Para la siguiente condición se utiliza la misma lógica pero aplicada a la condición de que se haya presionado la tecla de dirección Izquierda y no la Derecha.

 

Finalmente si no se presionó  ninguna de las dos teclas, seteamos nuestro frame actual a 6 que es donde se encuentra nuestro personaje parado y según la última dirección  se dibujará viendo a la derecha o a la izquierda.

 

 

Creación de constructores 

 

Ya que agregamos nuevos parámetros a nuestra clase AnimSprites.cs lo que quiero hacer es crear un nuevo constructor de la clase, primer porque quiero dejar algunos fijos en un constructor por default y segundo para tener la posibilidad de definir parámetros al crear un nuevo objeto. El primer constructor quedaría de la siguiente manera:

 

 

       publicAnimSprite()
        {
          XPos= 200;
          YPos= 200;
          Angulo=0;
          Origen= new Vector2(0,0);
      } 

 

Este constructor será  nuestro constructor por default y será llamada cuando no definamos ningún parámetro. Lo que hace es copiar en
nuestros parámetros del objeto los valores que quiero que tenga al crear cualquier objeto. 

 

Ahora vamos a crear el segundo constructor que tendrá el siguiente
código:

 

       publicAnimSprite(int PosX, int PosY,float Angle, Vector2 Origim)
        {
          XPos = PosX;
          YPos = PosY;
          Angulo = Angle;
          Origen = Origim;
       } 

 

A diferencia del anterior, este constructor recibe cuatro parámetros,
los cuales definen el estado iniciar del objeto a crear. Este
constructor no lo ocuparemos para este ejemplo pero puedes empezar a
hacer pruebas con él.

 

 

Carga de una imagen de Fondo.

 

Si ejecutas el programa ya podrás controlar a Megaman en ambas direcciones, sin ningún límite, es decir, puedes salirte de la pantalla en ambos lados. Lo que vamos a hacer ahora es cargar una imagen de fondo para olvidarnos del aburrido fondo blanco. Para eso he modificado una imagen que descargue del sitio Sprite-Resource para que ocupe toda la pantalla. La imagen en cuestión es la siguiente:

 

Fondo1 de megaman

 

Para cargar esta imagen vamos a hacer lo siguiente: Primero hay que cargar la imagen con el método que ya conocemos. Enseguida declaramos un objeto Texture2D dentro de nuestra clase Engine.cs para guardar ahí la imagen.

 

        private Texture2D Fondo1; 

 

A continuación agregamos el código para copiar la imagen en el objeto; esto lo haremos dentro del método LoadContent().

 

      Fondo1 = Content.Load<Texture2D>(”Sprites/Fondo1“);

 

Y por último vamos a agregar el código para dibujar el fondo en pantalla; Este código irá dentro del método Draw() y deberá copiarse antes del código que dibuja a nuestro personaje.

 

          spriteBatch.Begin();
              spriteBatch.Draw(Fondo1, new Vector2(0,0),Color.White);
           spriteBatch.End();

 

Lo que hacemos aquí es colocar la imagen de fondo en la coordenada (0,0) para que ocupe toda la pantalla.
Por último y para que haya congruencia del escenario con el personaje voy a modificar las coordenadas de inicio dentro del constructor por default  de nuestro personaje para que queden así:

 

           XPos = 100;
           YPos = 395;

 

Y listo, ya puedes controlar a Megaman con un escenario de fondo. Claro que ahorita no hay control de colisiones así que  puede atravesar paredes pero eso lo resolveremos en otro Post.

 

Si todo salió bien deberías de ver una imagen como la siguiente en pantalla completa:

 

Megaman con Fonfo1

 

Puedes bajar todo el proyecto y las imagenes de aqui (Proyecto Completo) o puedes bajar solo las imagenes para armar tú mismo el proyecto desde esta liga (Sprites2 de Megaman)

 

Espero que haya sido de su agrado este ejemplo y que haya quedado claro, como siempre si hay alguna duda no  olvides postearla, tampoco olvides tus comentarios antes de salir. Gracias y nos vemos en el siguiente post.

 

Piroshi.

 


Tags: ,

Powered by Wordpress
Theme © 2005 - 2009 FrederikM.de
BlueMod is a modification of the blueblog_DE Theme by Oliver Wunder