domingo, 4 de enero de 2009

Pacman 0.006 Con marcador

código pacman

Añadimos un marcador en nuestro juego en donde se muestre las vidas que les queda a nuestro Pacman y los puntos conseguidos.

Para esto, creamos una clase llamada "Marcador" que también es un sprite. Nuestro marcador es bastante sencillo, empleando la función "sprint.font.render" para crear una imagen con el texto indicado.

class Marcador (pygame.sprite.Sprite):
def __init__(self, pacman):
pygame.sprite.Sprite.__init__(self)
self.pacman = pacman
self.font = pygame.font.SysFont("None", 20)
self.rect = pygame.rect.Rect(0,0,0,0)


def update(self):
self.text = "vidas: %d, puntos: %d" %
(self.pacman.vidas, self.pacman.puntos)

self.image = self.font.render(self.text, 1,(255, 255, 0))
self.rect = self.image.get_rect()

#situamos al marcador en la esquina inferior derecha
self.rect.topleft =
(pygame.display.get_surface().get_width() -
self.rect.width,
pygame.display.get_surface().get_height() -
self.rect.height)

Un detalle, observa que le pasamos al constructor de la clase Marcador,  función "__init__", el sprite Pacman del que vamos a mostrar sus puntos y vidas. Estas dos propiedades se la añadimos a la clase Pacman.

class Pacman ( MiSprite ):
def __init__(self, fichero_imagen, pos_inicial):
MiSprite.__init__(self, fichero_imagen, pos_inicial, [0,0])
self.vidas = 3
self.puntos = 0

Además hacemos que cuando pacman se coma un objeto, se compruebe si este tiene asociado puntos y si es así, se los sumamos a los puntos de pacman

class Pacman ( MiSprite ):
...
def update (self):
...
global sprites
sprites_choque = pygame.sprite.spritecollide(self, sprites, False)
for sprite in sprites_choque:
if sprite != self:
if hasattr ( sprite, "comestible" ):
if sprite.comestible:
if hasattr ( sprite, "puntos" ):
self.puntos += sprite.puntos

sprite.kill() #destruimos el sprite

En la próxima entrega haremos que nuestro fantasma se mueva por toda la pantalla en busca de nuestro pacman.

viernes, 2 de enero de 2009

pacman 0.005 - Construyendo un laberinto

código pacman

En esta nueva entrega de desarrollo de un juego clásico de pacman usando Python y Pygame, vamos añadir paredes para poder construir un laberinto en el que pacman huye de los fantasmas mientras se va comiendo todo lo que encuentra.

Añadimos una nueva clase denominada "Pared" que heredera de la clase "Sprite". Lo particular de esta clase es que no cargaremos una imagen sino que se dibujará un rectángulo. Para hacer esto crearemos una superficie de dibujo con las dimensiones especificadas a través de una lista o tupla que indica ancho y alto, "pygame.Surface(dimension)", y a continuación la rellenaremos del color deseado, "image.fill(color)".

class Pared ( pygame.sprite.Sprite ):
def __init__(self, color, pos_inicial, dimension):
pygame.sprite.Sprite.__init__(self)

self.image = pygame.Surface(dimension)
self.image.fill(color)

self.rect = self.image.get_rect()
self.rect.topleft = pos_inicial
self.infranqueable = True

def update(self):
pygame.sprite.Sprite.update(self)

Además, queremos que las paredes no puedan ser atravesadas por pacman ni por los fantasmas. Para hacer esto, modificaremos la función "update" de la clase "MiSprite", comprobándose si el sprite choca contra otro sprite que presenta la propiedad "infranqueable". Observa que al final de la función "__init__" de la clase "Pared" hemos inicializado la propiedad "infranqueable" a True.

class MiSprite ( pygame.sprite.Sprite ):
...
def update (self):
#la funcion "copy" crea una copia del rectangulo
copia_rect = copy.copy(self.rect)

self.rect.move_ip ( self.velocidad[0], self.velocidad[1])

colisiones = pygame.sprite.spritecollide(self,
sprites,
False)
for colision in colisiones:
if colision != self:
if hasattr ( colision, "infranqueable" ):
if colision.infranqueable:
self.rect = copia_rect
return
...

Como lógica para manejar el choque con los objetos "infranqueables" hemos guardado la posición del sprite, movido el sprite y a continuación comprobado si choca contra un objeto. Si es así, volvemos el sprite a la posición original antes del choque.

Por último, creamos dos paredes en nuestro juego para probar nuestra nueva versión.

sprite = Pared ( [150,150,150], [72,72], [100,10] )
sprites.add ( sprite )

sprite = Pared ( [150,150,150], [172,172], [10,100] )
sprites.add ( sprite )
En la próxima entrega añadiremos un marcador a nuestro juego en donde se visualice los puntos y las vidas que les queda a nuestro pacman.

jueves, 1 de enero de 2009

pacman 0.004 - ¡A comer!

código pacman

Lo que haremos a continuación es enseñar a comer a nuestro pacman. La regla será que pacman se comerá todos los objetos (sprites) comestibles con los que se encuentre. Un sprite será comestible si tiene el atributo "comestible" y éste tiene valor "True" y pacman se lo comerá si colisiona con él.

Para ver los sprites con los que va colisionando nuestro pacman vamos a emplear la función "pygame.sprite.spritecollide". Esta función dado un sprite X y una lista de sprites devuelve los sprites de esta lista que colisiona con el sprite X. El tercer parámetro de esta función, que tenemos a False, indica si queremos que se eliminen automáticamente de la lista todos aquellos sprites con los que colisiona.

sprites_choque = pygame.sprite.spritecollide(spriteX,
sprites,
False)

Así quedará nuestra función "update" de Pacman. Para facilitar su lectura no la incluyo entera pero la puedes ver en el código que te adjunto

class Pacman ( MiSprite ):
...
def update (self):
...
MiSprite.update(self)

global sprites
sprites_choque = pygame.sprite.spritecollide(self,
sprites,
False)
for sprite in sprites_choque:
if sprite != self:
if hasattr ( sprite, "comestible" ):
if sprite.comestible:
sprite.kill() #destruimos el sprite

Por si no sabes mucho de Python, la función "hasattr" te permite comprobar si un objeto tiene definido un determinado atributo.

Destruimos un sprite llamando a su método "kill" que lo destruye eliminándolo de todas aquellas listas que lo contienen.

Para hacer que las cerezas y las bolitas sean comestibles basta con indicarlo a través del nuevo atributo "comestible".

sprite = MiSprite ("fruta.gif", [0, 100], [0,0])
sprite.comestible = True
sprites.add ( sprite )

sprite = MiSprite ("bola.gif", [100, 100], [0,0] )
sprite.comestible = True
sprites.add ( sprite )
En la próxima entrega veremos còmo crear paredes dentro de nuestro juego de tal forma que sean infranqueables.

pacman 0.003 - Controlando nuestro pacman

código pacman

Vamos a modificar nuestro juego Pacman para que el muñequito sea controlado por teclado. Además, para que no huyan los muñecos, limitaremos su movimiento a las dimensiones de la pantalla.

Como iremos introduciendo lógica particular para nuestro pacman, crearemos una clase específica para él. La nueva clase se llama "Pacman" y heredará de la clase "MiSprite". Por lo pronto, lo único que haremos es que en la función "update" trate los eventos de teclado y cambie la dirección del muñequito.

class Pacman ( MiSprite ):
def __init__(self, fichero_imagen, pos_inicial):
MiSprite.__init__(self, fichero_imagen, pos_inicial, [0,0])

def update (self):
global eventos
v = 1 #velocidad a la que se mueve nuestro pacman
for event in eventos:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.velocidad[0] = -v
self.velocidad[1] = 0
elif event.key == pygame.K_RIGHT:
self.velocidad[0] = v
self.velocidad[1] = 0
elif event.key == pygame.K_UP:
self.velocidad[1] = -v
self.velocidad[0] = 0
elif event.key == pygame.K_DOWN:
self.velocidad[1] = v
self.velocidad[0] = 0
elif event.key == pygame.K_SPACE:
pass

MiSprite.update(self)
Ya ves, muy sencillo, vemos si se produce un evento de tecla pulsada, comprobamos la tecla y si la tecla es de una de la de movimiento de cursor, cambiamos la dirección de nuestro pacman.

Además, vamos a modificar la función "update" de la clase "MiSprite" para que los muñecos no salgan fuera de nuestra pantalla.

class MiSprite ( pygame.sprite.Sprite ):
....
def update (self):
self.rect.move_ip(self.velocidad[0],self.velocidad[1])

screen = pygame.display.get_surface ()

if self.rect.top < 0:
self.rect.top = 0
self.velocidad[1] = 0
elif self.rect.bottom > screen.get_height():
self.rect.bottom = screen.get_height()
self.velocidad[1] = 0

if self.rect.left < 0:
self.rect.left = 0
self.velocidad[0] = 0
elif self.rect.right > screen.get_width():
self.rect.right = screen.get_width()
self.velocidad[0] = 0
No creo que haga falta comentar el código, es también muy sencillo. Se comprueba si el rectángulo de la imagen desborda algún lado de la pantalla y si es así, la modificamos para que no se salga de la pantalla.

Para la próxima entrega haremos que nuestro pacman pueda comer determinados objetos del juego.

miércoles, 31 de diciembre de 2008

Pacman 0.002 - Los eventos

código pacman

Continuando con nuestro juego en Python, vamos a introducir el manejo de eventos. Los eventos son desde cambio de la ventana hasta teclas pulsadas, pasando por movimiento del ratón. Para hacernos una idea de los tipos de eventos, lo que vamos hacer es simplemente capturarlos y mostrarlos en pantalla. Para probarlo, ejecuta el juego y pulsa teclas, mueve el ratón, etc.

En la primera versión de nuestro pacman, parecía que nuestro juego se quedaba "colgado". Esto se debe a que no procesábamos los eventos.

Los eventos van quedando almacenados en una cola, a la espera de que los procesemos. Para recuperar todos los eventos empleamos la función "pygame.event.get()" que devuelve una lista con todos los eventos y los elimina de la cola original. Esto lo haremos en todas las iteraciones del bucle principal de nuestro programa.

  while True:
eventos = pygame.event.get()
ManejarEventos ()

sprites.update ()
sprites.clear (screen, background)
pygame.display.update (sprites.draw (screen))

reloj.tick (60) #tiempo de espera entre frames

A continuación, en nuestro ejemplo, vamos a llamar a la función "ManejarEventos()" que lo único que hace es mostrar en pantalla el tipo de evento y además chequea si se produce el evento de tipo "Quit" que da por terminado el juego. Este tipo de evento se produce por ejemplo cuando pulsamos sobre la "X" de la ventana para cerrarla.

def ManejarEventos():
global eventos
for event in eventos:
print event
if event.type == pygame.QUIT:
sys.exit(0) #se termina el programa
elif event.type == pygame.MOUSEBUTTONDOWN:
print event.pos


En las próximas entradas de este blog lo que haremos es permitir que pacman sea manejado con el teclado y que pueda comerse las otras piezas del juego.

martes, 30 de diciembre de 2008

Pacman 0.001 - Aprender a programar es divertido

código pacman

Vamos a programar nuestra primera versión de pacman en Python 2.6 y usando la librería "Pygame". En esta primera versión lo que haremos es mostrar en una pantalla negra las imágenes que se muestran a continuación.





Además, haremos que nuestro pacman y el fantasma se muevan por la pantalla.

Todo el código y las imágenes lo tienes en el siguiente fichero pacman

Todos los objetos que mostremos en pantalla serán "sprites". Un sprite es un objeto que tiene dos propiedades: image y rect. "image" es la imagen a mostrar y "rect" es el rectángulo en donde se muestra la imagen en pantalla.
La función "update" de los sprites es llamada de forma continua a lo largo del juego para poder hacer cualquier cambio. Por ejemplo, en nuestro caso cambiamos la posición del sprite en pantalla empleando la función "move_ip" que desplaza el rectángulo de la imagen según la velocidad indicada en el constructor del sprite.
Por si no conoces Python, la función "__init__" es el constructor de la clase.
import pygame

class MiSprite ( pygame.sprite.Sprite ):
def __init__(self, fichero_imagen, pos_inicial, velocidad):
pygame.sprite.Sprite.__init__(self)

self.image = pygame.image.load(fichero_imagen).convert()
self.rect = self.image.get_rect()

self.rect.topleft = pos_inicial
self.velocidad = velocidad

def update (self):
self.rect.move_ip ( self.velocidad[0], self.velocidad[1])
Una vez definida nuestra clase Sprite vamos a inicializar el juego y la pantalla. Creamos una copia de la pantalla como "background" para optimizar el redibujado.
pygame.init()

window = pygame.display.set_mode([300,400])
pygame.display.set_caption("pacman")

screen = pygame.display.get_surface()
screen.fill ([0,0,0])

background = screen.copy()
A continuación creamos los sprites que se muestran en pantalla. Almacenamos los sprites en una lista de tipo "RenderUpdates" que optimiza el redibujado en pantalla.
sprites = pygame.sprite.RenderUpdates()

sprite = MiSprite("pacman.gif", [0,0], [1,1])
sprites.add ( sprite )

sprite = MiSprite("fantasma.gif",[100,0], [1, 1])
sprites.add ( sprite )

sprite = MiSprite ("fruta.gif", [0, 100], [0,0])
sprites.add ( sprite )

sprite = MiSprite ("bola.gif", [100, 100], [0,0] )
sprites.add ( sprite )
Por último, ejecutamos un bucle infinito en donde se actualizarán los sprites y se redibujarán en pantalla.
reloj = pygame.time.Clock()

while True:
sprites.update ()
sprites.clear (screen, background)
pygame.display.update (sprites.draw (screen))
reloj.tick (60) #tiempo de espera entre frames
En próximas entradas iremos mejorando nuestro pacman.

lunes, 29 de diciembre de 2008

!Quiero aprender a programar divirtiéndome!

La forma tradicional de aprender a programar es muy muy aburrida, con los típicos ejemplos de búsquedas de texto, ordenaciones, etc. !Quiero aprender a programar divirtiéndome!

¿Cómo? Pues bien sencillo, programando un juego. ¡Ojo! Un juego visual, nada de pantallas de consola con letritas. ¡Uff! Seguro que piensas que eso es muy complejo, sobre todo para enseñárselo a tus alumnos que no tienen ni idea de programación. Pues es mucho más fácil de lo que puedas pensar, todo consiste en elegir las herramientas adecuadas. ¿Y qué herramientas son esas? Python y Pygame. Python es un lenguaje de script cuyo uso se está extendiendo en todos los ámbitos y Pygame es una librería para programar juegos en Python.

La metodología que te propongo es ir creando con los alumnos la estructura básica de un comecocos para luego ir añadiendo nuevas funcionalidades al juego mientras los alumnos descubren toda la potencialidad de Python.
Se puede ver un video demostrativo del juego que vamos a crear. Los saltos que se aprecian son debido a la baja calidad de la grabación para que no ocupase demasiado.




En las próximas entradas de este blog, iré creando este comecoco. Por lo pronto, ya puedes ir instalándote Python y Pygame.