viernes, 24 de mayo de 2013

Tutorial Pygame parte 1

Bien,vamos a comenzar los tutoriales de creación de Juegos con Python usando la librería de pygame :D,algo que mas me gusta a la hora de programa es programar script's para sistemas Unix en Python,Perl,Bash,Lua,etc y últimamente estoy viendo pygame,una librería que conocía desde hace tiempo pero que no había probado muy a fondo,he tenido alguna experiencia programando juegos en lua para Windows y no se me complico tanto para entender el funcionamiento de pygame,así que les comparto lo que he aprendido y lo haré lo mas detalladamente posible y iremos al grano de programación (0 teoría) ,la teoría o las cuestiones mas técnicas fácilmente las pueden googlear así que iniciemos.

Tutorial

Este tutorial tiene previsto que ya sabes python, así que si no entiendes las partes fundamentales del lenguaje hecha un vistazo al espacio de python en Tiempo de Tux esta todo lo necesario sobre este lenguaje para entender este y los futuros tutoriales de pygame.

Enlace

Primero que nada yo uso Linux en especifico Gentoo/Debian/Arch, así que si usas windows ve la documentación de instalación de python en la pagina oficial, pero el tutorial de programación te funcionara.

Instalación:

En Debian:

sudo aptitude install pygame

En Gentoo

sudo emerge -av dev-python/pygame

Archlinux

sudo pacman -S python-pygame

Para otros sistemas googlen la instalación de pygame.

Creamos un documento de texto con nombre ejemplo1 y extension .py,ahora lo abrimos con nuestro editor de texto favorito,en mi caso uso Vim o Gedit.

1.Primero que nada vamos a importar lo necesario y definir lo necesario:

# el hash

! el bang

/usr/bin/env la ruta de env

python y el nombre de python

Nota. Si usas una distro muy actual como Arch (por ejemplo) python ya es python 3 y aquí usaremos python 2.7 así que en el nombre usaremos python2

Ve en terminal:

python -V

Si sale 3.x usa python2 en el nombre de python,si dice 2.x  usa solo python en el nombre.

Asi queda el hashbang:

#!/usr/bin/env python2

Enseguida definimos la codificación utf-8 para poder usar caracteres especiales:

# -*- coding: utf-8 -*-

Por ultimo importamos pygame en el espacio de las importaciones:

import pygame

Tambien sys para poder salir del juego cuando este en ejecución:

import sys

Bien,se recomienda usar una función main para el bloque principal de pygame,en mi caso y en estos tutoriales no ya que no es necesario.

Iniciamos definiendo las constantes del programa:

Primero nuestra pantalla:

La pantalla del videojuego es una ventana común y corriente en tamaño así que lleva las medidas alto y ancho:

Definiremos una tupla con las medidas y al mismo tiempo dos variables para poder usarlas:

size = alto,ancho = 400,400

Abajo de las constantes debemos inicializar todos los eventos de pygame con su función init:

pygame.init()

Con esto llamamos a pygame a la acción.

En un juego al igual que en la mayoría de los programas debemos crear un bucle principal que lo mantenga abierto en lo que ejecutamos su contenido,para hacer mas legible el código vamos a definir una variable que diga que estamos jugando:

jugando = True

Ahora iniciamos el bucle con la condición de la variable jugando:

while jugando:

Ahora completamos la condición while con else(while/else):

Debe quedar así:

 while jugando:  
   #juego  
 else:  
   sys.exit(0) # Para cuando dejemos de jugar cierre el juego  

Bien,en el bloque while vamos a anidar un bucle for que recorra los eventos de la lista que nos regresa pygame.event.get():

for eventos in pygame.event.get():

Pygame se manipula a base de eventos,estos son desde la entrada del teclado hasta posibles ocurrencias del sistema.

Añadimos una estructura selectiva en el bloque for,para manipular el evento QUIT de pygame,que es cuando cerramos la ventana desde el window manager(al darle a la x de la ventana):

if eventos.type == QUIT:
    jugando = False

Creamos un elif para el mismo grupo de eventos,esta vez sera para ver si un botón esta presionado ya que hay dos posibles eventos para los botones:

KEYDOWN # Cuando apretamos un botón
KEYUP # Cuando soltamos un botón (primero debemos presionarlo)

Así que esa estructura va asi:

elif eventos.type == pygame.KEYDOWN:

Ahora anidamos en esa estructura otra estructura,para ver que tecla presionamos,en este caso vamos a usar la tecla q para salir y la tecla esc:

if eventos.key == pygame.K_q or eventos.key == pygame.K_ESCAPE:
    jugando = False

Abajo de pygame.init() llamamos la ventana:

Para llamar la ventana o abrirla mejor dicho, debemos usar la función display.set_mode(tupla) pasandole una tupla o lista como parámetro de alto y ancho,como ya la definimos anteriormente, la abrimos definiendo una variable que usaremos en el futuro, así:

sreen = pygame.display.set_mode(size)

Y le podemos poner nombre a la ventana con la función pygame.display.set_caption(nombre)

pygame.display.set_caption("Ejemplo 1")

De momento solo vamos a ver como cerrar la pantalla,no necesitamos otro bloque de selección:

Esto va así en este momento:
 #!/usr/bin/env python2  
 # -*- coding: utf-8 -*-  
   
 import pygame  
 import sys  
   
 size = alto,ancho = 400,400  
   
 pygame.init()  
   
 sreen = pygame.display.set_mode(size)  
 pygame.display.set_caption("Ejemplo 1")  
   
 jugando = True  
   
 while jugando:  
   for eventos in pygame.event.get():  
     if eventos.type == pygame.QUIT:  
       jugando = False  
     elif eventos.type == pygame.KEYDOWN:  
       if eventos.key == pygame.K_q or eventos.key == pygame.K_ESCAPE:  
         jugando = False  
 else:  
   sys.exit(0)  
   

   
Es hora de ejecutarlo:

python ejemplo1.py
Nota: La misma advertencia de python,si python ya es 3.x ejecuta:
python2 ejemplo1.py


Es tiempo de colocar una imagen que a la ves nos servirá para analizar la ruta de una imagen en la posición x(horizontal) y y(vertical) :

Añadimos esta función arriba de pygame.init() :

 def cargar_imagen(nombre,alfa=False):  
   imagen = pygame.image.load(nombre)  
   if alfa == True:  
     imagen = imagen.convert_alpha()  
   else:  
     imagen = imagen.convert()  
   return imagen  

Esa función recibe dos parámetros la ruta o nombre de la imagen y si necesita transparencia,las imágenes con transparencia son los objetos que moveremos en el juego,en este caso no usare fondo pero para el fondo se usa:

imagen = imagen.convert()

Y para los objetos:

imagen = imagen.convert_alpha()

Pero para ambos siempre iniciando la variable imagen con el valor de pygame.image.load(nombre) (donde nombre,es el nombre o ruta a partir de la carpeta actual).

imagen = pygame.image.load("objeto.png")

Abajo de la función vamos a crear una clase (que heredara pygame.sprite.Sprite), que sera el objeto que moveremos:

Los sprites son la forma de tratar con los objetos en pygame(googlear para mas info)

 class Objeto(pygame.sprite.Sprite):  
   def __init__(self):  
     pygame.sprite.Sprite.__init__(self)  

Adentro de la clase cargaremos la imagen con la función que creamos anteriormente:

self.imagen = cargar_imagen("objeto.png",alfa=True)

Le añadimos el rect que es la posición en la que se encontrara al iniciar:

Primero hacemos un get a la imagen y luego lo definimos:

 self.rect = self.imagen.get_rect()  
 self.rect.centerx = alto / 2  
 self.rect.centery = ancho / 2 # De esta manera lo colocara en medio de la pantalla  

Asi queda nuestro programa hasta ahora

 #!/usr/bin/env python2  
 # -*- coding: utf-8 -*-  
   
 import pygame  
 import sys  
   
 size = alto,ancho = 400,400  
   
 def cargar_imagen(nombre,alfa=False):  
   imagen = pygame.image.load(nombre)  
   if alfa == True:  
     imagen = imagen.convert_alpha()  
   else:  
     imagen = imagen.convert()  
   return imagen  
   
 class Objeto(pygame.sprite.Sprite):  
   def __init__(self):  
     pygame.sprite.Sprite.__init__(self)  
     self.imagen = cargar_imagen("objeto.png",alfa=True)  
     self.rect = self.imagen.get_rect()  
     self.rect.centerx = alto / 2  
     self.rect.centery = ancho / 2  
   
 pygame.init()  
   
 screen = pygame.display.set_mode(size)  
 pygame.display.set_caption("Ejemplo 1")  
   
 jugando = True  
   
 while jugando:  
   for eventos in pygame.event.get():  
     if eventos.type == pygame.QUIT:  
       jugando = False  
     elif eventos.type == pygame.KEYDOWN:  
       if eventos.key == pygame.K_q or eventos.key == pygame.K_ESCAPE:  
         jugando = False  
 else:  
   sys.exit(0)  

Arriba del bucle while vamos a cargar las imagenes,primero instanciamos el objeto:

objeto = Objeto()

Luego cargamos su imagen definiendola en una variable,para poder trabajar con ella en el futuro:

imagen_objeto = objeto.imagen

Adentro del bloque del buble while,abajo del for hacemos un blit sobre la pantalla,que sera lo que cargara la imagen:

Le tenemos que pasar dos valores(en este caso),la imagen(Surface) y una lista o tupla con la posición X y Y:

Para la imagen(Surface) usamos la variable de la imagen y para la posición usamos la lista de clase (rect) del objeto objeto:

screen.blit(imagen_objeto,objeto.rect)

Ahora redibujamos la pantalla haciendo flip:

pygame.display.flip()

Ahora ejecutamos:

python ejemplo1.py

Si da error es porque no tenemos un objeto.png en esa carpeta,usen este :



Guardalo en la carpeta del juego



Ahora vamos a añadir un texto para saber donde se encuentra,en posición x y (y)

Pero primero vamos a cargar un fondo de color,en la zona de las constantes añadimos una lista con el color rgb:

color = [119,255,221]

Si no saben colores RGB o no recuerdan pueden visitar esta web:

http://coloreminder.com

Cargamos un font arriba del bucle while:

Se le pasan dos parámetros el nombre de la fuente y el tamaño,en mi caso si uso None carga la fuente por defecto y el tamaño le daremos 15:

font = pygame.font.Font(None,15)

Definimos una constante en la parte de las constantes con las variables que serán la posición del objeto:

vertical,horizontal = 0,0

En el bloque del bucle while añadimos el texto al font:

Primero definimos un texto,que en este caso sera la posición del objeto:

posicion = "x : %d y : %d" % (horizontal,vertical)

Se le pasan tres parámetros,el primero es el texto,el segundo es un boleano para definir los bordes lisos,el tercero es el color del texto en RGB:

text = font.render(posicion,1,(255,255,255))

Dibujamos la pantalla,abajo del bucle for fuera de este:

screen.fill(color)

Hacemos un blit al texto:

screen.blit(text,(20,20))

Por ultimo en la clase Objeto definimos las variables globales horizontal y vertical en un método update para que cambie:

 def update(self):  
   global horizontal,vertical  
   horizontal = self.rect.centerx  
   vertical = self.rect.centery  

Ahora debajo del bucle while añadimos el update del objeto:

objeto.update()

En estos momentos el script va asi:

 #!/usr/bin/env python2  
 # -*- coding: utf-8 -*-  
   
 import pygame  
 import sys  
   
 size = alto,ancho = 400,400  
 vertical,horizontal = 0,0  
 color = [119,255,221]  
   
 def cargar_imagen(nombre,alfa=False):  
   imagen = pygame.image.load(nombre)  
   if alfa == True:  
     imagen = imagen.convert_alpha()  
   else:  
     imagen = imagen.convert()  
   return imagen  
   
 class Objeto(pygame.sprite.Sprite):  
   def __init__(self):  
     pygame.sprite.Sprite.__init__(self)  
     self.imagen = cargar_imagen("objeto.png",alfa=True)  
     self.rect = self.imagen.get_rect()  
     self.rect.centerx = alto / 2  
     self.rect.centery = ancho / 2  
   def update(self):  
     global horizontal,vertical  
     horizontal = self.rect.centerx  
     vertical = self.rect.centery  
   
 pygame.init()  
   
 screen = pygame.display.set_mode(size)  
 pygame.display.set_caption("Ejemplo 1")  
   
 jugando = True  
 objeto = Objeto()  
 imagen_objeto = objeto.imagen  
   
 font = pygame.font.Font(None,30)  
   
 while jugando:  
   objeto.update()  
   posicion = "x : %d y : %d" % (horizontal,vertical)  
   text = font.render(posicion,1,(255,255,255))  
   for eventos in pygame.event.get():  
     if eventos.type == pygame.QUIT:  
       jugando = False  
     elif eventos.type == pygame.KEYDOWN:  
       if eventos.key == pygame.K_q or eventos.key == pygame.K_ESCAPE:  
         jugando = False  
   screen.fill(color)   
   screen.blit(text,(20,20))  
   screen.blit(imagen_objeto,objeto.rect)  
   pygame.display.flip()  
 else:  
   sys.exit(0)  

Ya podemos ejecutarlo:

python ejemplo1.py



Vamos a mover el objeto en la pantalla,para ello vamos a añadir los eventos necesarios:

En el bucle for en la estructura (elif eventos.type == pygame.KEYDOWN:)

Añadimos los sigiuentes elif's para manegar los eventos:

 elif eventos.key == pygame.K_LEFT:  
   objeto.rect.centerx -= 5  
 elif eventos.key == pygame.K_RIGHT:  
   objeto.rect.centerx += 5  
 elif eventos.key == pygame.K_UP:  
   objeto.rect.centery -= 5  
 elif eventos.key == pygame.K_DOWN:  
   objeto.rect.centery += 5  

Con eso manejaremos las pulsaciones de las cuatro direcciones,añadiendo 5 o disminuyendo 5 en la posición del objeto,recuerda que x es horizontal y (y) vertical.

Arriba del bucle while añadimos la repetición de las pulsaciones del teclado,que funcionaran para el movimiento o autofire en un juego de disparos:

pygame.key.set_repeat(1,20)

Con eso ya tenemos una buena herramienta para ver donde esta un objeto en la pantalla,vamos a hacerlo mas interesante,vamos a cambiar el color de la pantalla con la pulsación de la tecla (c)

Primero que nada creamos un modulo,que nos encuentre los colores RGB,yo programe este que usa colores grises,pueden modificarlo pero de momento así funciona:

 # -*- encoding: utf-8 -*-  
   
from random import randint  
   
def colores():  
  colors = 0  
  col = []  
  rgb = []  
  while (colors < 256):  
    col.append(colors)  
    colors += 8  
  col.append(255)  
  n = randint(0, len(col) - 1)  
  for i in range(0,3):  
    rgb.append(col[n])  
  return rgb  
   

Lo metemos en un archivo con nombre (colores.py) en la carpeta donde esta ejemplo1.py

Ahora en el ejemplo importamos los colores:

import colores

Y en la estructura de pulsacion de teclas añadimos este elif:

 elif eventos.key == pygame.K_c:  
   pygame.key.set_repeat(1,40) # Esto para detener las multiples pulsaciones(autofire)  
   color = colores.colores()  
   pygame.key.set_repeat(1,20) # Esto para devolver las pulsaciones de movimiento  

Eso es todo en este tutorial,el código final queda así:



Si tienen problemas de identacion/sangria identen manualmente el código.



3 comentarios:

  1. De lujo bro, man, algo off-topic, podrias compartir el conkyrc que vos anda usando?

    Saludos!

    ResponderBorrar

Los comentarios serán revisados antes de ser publicados.