miércoles, 10 de octubre de 2012

Reporte de la Semana 5

De acuerdo a nuestra calendarización, los objetivos a cumplir en esta semana son:
  • Animación de Personaje(Básica)
  • Movimientos de personaje dummy en pyGame
  • Side-Scrolling
  • Creación de Objetos Estáticos (Prototipos)
  • Interacción del personaje dummy con Objetos
Adición de un personaje en pyGame

Como habiamos mencionado anteriormente, el juego será 2D, por lo que para crear las animaciones de los personajes en el juego se utilizarán spritesheets, que no son más que imágenes de los personajes en diferentes posiciones. Por ejemplo, para las pruebas que estamos realizando, utilizamos el siguiente spritesheet de Scott Pilgrim:


Como se puede ver en esta imágen se encuentra el mismo personaje en diferentes posiciones.

Entonces si queremos crear la animación del personaje en movimiento, localizamos todos los sprites que contienen esta animación por separado dentro de la imágen, que son los siguientes:


Para cada uno, localizamos las coordenadas x, y de la parte superior izquierda del rectángulo que pueda cubrir todo el sprite. También, definimos un ancho y un largo, que a partir de los puntos previos se extenderá para encuadrar al sprite, cuidando que toda la imágen del sprite quede dentro del rectángulo.

Entonces si el spritesheet fuera la imágen anterior, las coordenadas del primer sprite serían:

Estos 4 datos son escritos en un archivo, que se llamará nombre.coords, donde nombre es el mismo nombre de la imágen que se usará como spritesheet. El archivo contiene en cada línea el siguiente formato:

nombre_animación (x1, y1, ancho1, largo1) (x2, y2, ancho2, largo2) ... (xn, yn, anchon, largon)
    • nombre_animación es el nombre de la animación que se creará con las coordenadas.
    • Las x, y son las coordenadas de inicio en el spritesheet para crear el rectángulo del personaje.
    • ancho y largo son las dimensiones que tomará el rectángulo a partir de las coordenadas de inicio.
Con este archivo, el programa cargara un vector con todas las coordenadas de las animaciones que se usarán para un determinado personaje. Algunos ejemplos de animaciones:



Movimiento

Moverlos dentro de la pantalla no es difícil, ya creados los vectores con las animaciones. Para esto se usa el teclado, moviendo con las flechas direccionales al personaje hacia la derecha o izquierda. Cuando se presiona una tecla, se empieza a incrementar una variable cada cierto tiempo. Cada que se incrementa se muestra un diferente sprite, creando la animación. Además dependiendo de la dirección a la que se quiere mover, se mueven las coordenadas del personaje en la pantalla a una velocidad determinada.

Es importante checar que estas coordenadas no salgan del tamaño de la ventana, y si es así basta con regresarlo dentro. A continuación se puede ver el movimiento del personaje dentro de la ventana:


Adición-interacción de objetos estáticos en pyGame

Ahora para agregar items en la ventana, basta con tomar la imagen que se usará para el item y asignarle unas coordenadas dentro de la ventana. En el caso del ejemplo estas coordenadas son aleatorias. Lo importante ahora es añadir interacción con este objeto. 

Debido a que estamos utlizando la clase sprite de pyGame, esto es sencillo. Para cada objeto-personaje en el juego debemos de guardar un Rect, que es un objeto que contiene datos del rectángulo "virtual" que cubre cada objeto-personaje. Entonces en este caso el personaje tiene su propio rect, y el item txambién lo tiene. Lo que hacemos es utilizar colliderect para checar si el personaje entro en contacto con el item, y si es así, un evento debe ocurrir, en este caso un contador se incrementa y el item vuelve a aparecer aleatoriamente en algún lugar del mapa.

Esta interacción puede observarse a continuación:


Side-Scrolling

Una parte importante del juego es el side-scrolling, es decir, mover el mapa conforme va avanzando el personaje. Para esto es necesaria una imágen enormememte larga que represente el fondo del mapa. En el caso de este ejemplo, se usó la siguiente:


Al igual que los sprites quizás sea necesario definir donde empieza y donde termina el mapa real, debido a que la imágen contiene otros datos además del mapa.

Lo siguiente es detectar cada que un personaje se acerca al limite de la pantalla, ya sea izquierdo o derecho(si el juego tiene scrolling vertical también sería necesario checar eso). Para esto checamos la posición del personaje y sumamos 100 a su coordenada en x para checar si esta cerca del lado derecho, o restamos 100 para checar el lado izquierdo. También es necesario saber en que parte del mapa estamos, por lo cual debemos ir guardando las coordenadas actuales del mapa conforme se va haciendo scroll, para no salir del inicio o el final.

Cada que el programa detecte que el personaje se acerca a algún lado de la pantalla, se hace el scroll aumentando las coordenadas en x del mapa que se estan tomando para el fondo. Esto se puede observar a continuación:



Referencias:

miércoles, 12 de septiembre de 2012

Reporte de la Semana 4

Para la Semana 4 los objetivos a cumplir fueron:

  • Creación de Prototipo de Personaje
  • Creación de Prototipo de Mapa (Por votación decidimos separar la parte del mapa de blender, lo que mencionaremos más adelante)
  • Investigación sobre pyGame y Sprites
Creación de un Prototipo de un Personaje

Para poder mostrar más las capacidades de Blender para el modelado gráfico, buscamos modelar a una persona en el mismo, usando una plantilla del cuerpo humano como fondo para poder simplemente seguir las lineas utilizando figuras. La plantilla usada fue esta:


Entonces la idea de esto esta en crear todo a partir de cubos. Inicialmente colocamos uno en el centro del cuerpo de frente, puede ser en el área del estómago o el pecho pero es necesario que esté centrado. Para poder llevar a cabo el diseño de una forma más detallada en Blender se separa la vista en dos para poder al mismo tiempo ir modelando el cuerpo de lado. Como se puede ver:


El resto es ir "estirando" o el termino de Blender (extruding) el mismo cubo hacia arriba y abajo, ajustando para poder crear el torso, piernas y cabeza. La parte de las manos entonces se hace lo mismo, pero partiendo de un lado del torso, estirando algunos vértices para poder crearla.

El resultado final quedó así:



Investigación de nuevas formas de crear mapas

Debido a que vimos que la creación de mapas en Blender, y el hecho de darle física junto con pygame sería bastante complicado (y agregando el hecho que estamos cortos de personal) decidimos buscar nuevas alternativas para la creación de mapas:
  • Uso de Matrices 

    Una de las formas para crear mapas sería el uso de una matriz para representarlo. El gran pro a favor de esto es que ya teniendo una sólida base para la creación de mapas de esta manera, será MUY simple crear muchos más. 

    Este método funciona creando una matriz, puede ser manualmente. Ésta matriz debe contener números que representen alguna parte del mapa. Por ejemplo para algo sencillo podemos representar el número 0 como las partes solidas de un mapa, el suelo. paredes, techo, y el número 1 para el espacio por el cual podemos caminar. Entonces iterando esta matriz, podemos ir dibujando en cada posición dichos objetos, y más adelante agregándole lógica a cada uno crear un nuevo mapa.
    Un ejemplo que hicimos nosotros de éste método es el siguiente:


Investigación sobre pyGame y Sprites
  • Uso de Grupos
La clase grupo sirve de contenedor para los sprites. Similar a ellos, tiene una función add() y remove() con las cuales se puede cambiar cuales sprites pertenecen al grupo. También se puede pasar un sprite o una lista de sprites al método constructor para crear una instancia de un grupo que contenga algunos sprites iniciales.

Otros métodos que tiene son empty() para remover todos los sprites del grupo, copy() que retorna una copia del grupo con todos los miembros y has() que checa si el grupo contiene un sprite o una lista de sprites. Otro método usado frecuentemente es sprites() que retorna un objeto que puede ser iterado para accesar a cada sprite en el grupo. También existe un método update que llama a update() para cada sprite del grupo. 

Los grupos serían muy útiles en el proyecto ya que en ellos de podrían guardar los diferentes objetos y personajes del juego teniendo una cierta clasificación, por ejemplo enemigos, aliados, objetos usables, etc. 

Además al ser un juego tipo beat 'em up, muchas veces existen situaciones en las que tienes que derrotar a todos los enemigos en un área para poder avanzar. Usando grupos podríamos crear uno donde cada sprite sea un enemigo de estos, y así podemos remover los sprites de los enemigos derrotados y permitir el avance cuando el grupo este vació.

Detección de Colisiones


La clase sprite contiene un par de funciones que pueden ser útiles para implementaciones sencillas de colisiones:
  • spritecollide(sprite, group, dokill) -> list
    Este método verifica colisiones entre un solo sprite con todos los de un grupo. El método retorna una lista con los sprites que se están sobreponiendo con el sprite especificado. 
  • groupcollide(group1, group2, dokill1, dokill2) -> dictionary
    Es un método como el anterior pero más complejo, ya que verifica por colisiones en cada sprite de un grupo, con colisiones con cada sprite de otro segundo grupo.
Enlaces Útiles: