Contribuyentes

lunes, 17 de enero de 2011

Python (programación de videojuegos con pygame III)

Continuamos con el desarrollo de nuestro juego con python y su módulo pygame, en el post anterior creamos nuestro entorno del juego (la ventana), en esta ocasión cargaremos la interfaz gráfica en la pantalla, así como desarrollaremos el entorno del jugador (la pala) y el comportamiento de la bola en nuestro juego.
En nuestro código anterior le modificaremos para tener un método que nos permita maniobrar con imágenes, este soporte nos los brinda de manera parcial pygame, por lo que nuestro código a desarrollar es el siguiente:
#Metodo para cargar una imagen a nuestro juego 
#de manera semiautomatica
def cargar_imagen(nombre, transparent = False):
    """metodo para cargar una imagen dada su 
    ubicacion"""
    try:
        #intentamos cargar la imagen por su ubicacion
        #si no funciona mandamos un error
        imagen = pygame.image.load(nombre)
    except pygame.error, message:
        raise SystemExit, message
    #Optimizamos la calidad de la imagen, para
    #que esta no influya en de manera sustancial
    #en el consumo de recursos
    imagen = imagen.convert()
    if transparent:
        color = imagen.get_at((0,0))
        imagen.set_colorkey(color,RLEACCEL)
    return imagen

este método nos permite maniobrar de manera sencilla con las imágenes, para que veamos como funciona modificaremos nuestro método "Game_loop" para que nos cargue el fondo de pantalla para nuestro remake, antes de mostrar el código modificado, es necesario crear un directorio con el nombre images, donde pondremos los gráficos de nuestro juego (sprites), y la imagen a mostrar en el juego es la siguiente:

Ya que tenemos nuestra imagen base mostraré el código modificado, el cual es el siguiente:

#metodo que contiene a nuestro "Game Loop"
def game_loop ():
    #Creamos la ventana y la asignamos a una variable
    pantalla = pygame.display.set_mode((ANCHO,ALTO))
    #Le ponemos nombre a nuestra ventana
    pygame.display.set_caption("Remake de pong")
    #cargamos la imagen y la almacenamos en una variable
    fondo = cargar_imagen('images/fondo_pong.png')
    while True:  
        for eventos in pygame.event.get():
            if eventos.type == QUIT:
                sys.exit(0)
        #anadimos la imagen a la pantalla
        pantalla.blit(fondo,(0,0))
        #actualizamos la pantalla
        pygame.display.flip()
    return 0

Ya que tenemos modificado a nuestro archivo, lo ejecutamos y vemos el resultado de nuestra modificación, el cual se asemejará a ésta imagen:

¡Bien! Ahora nuestra aplicación se va asemejando cada vez al clásico Pong, por lo que ahora crearemos a la pala del jugador y a la bola de juego, para esto los desarrollaremos como clases que permitirán crear un conjunto de instancias de clases para nuestros propósitos, los cuales son el desarrollar la pala y la bola. Las imágenes de la pala y la bola son las siguientes, de igual forma las almacenaremos en el directorio images.



El código de la clase Pala es la siguiente:
#Clase Pala, esta es usada tanto para el jugador, como 
#por la computadora para poder jugar
class Pala(pygame.sprite.Sprite) :
    """Clase Pala: hereda atributos directamente de la clase 
    Sprite, que se encuentra en el paquete pygame.sprite"""

    #Metodo constructor de la clase, el parametro self es utilizada
    #por todos los metodos de cualquier clase, y el parametro
    #centerx es para indicarle a que altura del eje x iniciaremos a nuestra 
    #pala (esta es una analogia con el plano cartesiano)
    def __init__ ( self, centerx ):

        #inicializamos al metodo constructor de nuestra clase padre
        pygame.sprite.Sprite.__init__(self)
        
        #cargamos la imagen de la pala y la guardamos en una variable
        self.image = cargar_imagen("images/pala.png")
        
        #esta variable nos sirve para poder interactuar con los elementos
        #dentro de nuestro juego
        self.rect = self.image.get_rect()
        
        #indicamos la altura en el eje x
        self.rect.centerx = centerx
        
        #indicamos de manera default donde estara en el eje Y
        self.rect.centery = ALTO / 2
        
        #velocidad usada cuando apretemos una tecla
        self.speed = 0.5

    #metodo que permitira manipular a la pala
    def mover ( self, time, keys ):
        
        #las siguientes condicionales nos permitiran
        #que nuestra pala se mueva y ademas no se salgan
        # de la pantalla
        if self.rect.top >= 0 :
            if keys[K_UP] :
                self.rect.centery -= self.speed * time
        if self.rect.bottom <= ALTO:
            if keys[K_DOWN] :
                self.rect.centery += self.speed * time

    #Metodo que controlara nuestra computadora de manera automatica
    #es decir, la inteligencia artificial de nuestro oponente
    def ia( self, time, ball ):
        #Estas condicionales sirven para detectar el movimiento de 
        #la bola y entonces poder realizar una accion
        if ball.speed[0] >= 0 and ball.rect.centerx >= ANCHO/2 :
            if self.rect.centery < ball.rect.centery :
                self.rect.centery += self.speed*time
            if self.rect.centery > ball.rect.centery :
                self.rect.centery -= self.speed*time

El código anterior es el nuestra pala y como poder moverla en nuestro juego, así como la inteligencia artificial sencilla que nos permite crear un oponente controlado por computadora.
El siguiente código va a ser el de nuestra bola, que se moverá tal y como lo hacía en aquel entrañable juego que era el Pong

#Clase Bola, la cual permite tener una bola que se mueve de manera natural 
#en el juego
class Bola(pygame.sprite.Sprite) :
    """Clase Bola: hereda atributos directamente de la clase 
    Sprite, que se encuentra en el modulo pygame.sprite"""
    
    #Metodo constructor de la bola, no tiene ningun parametro
    def __init__ ( self ):
        #cargamos la imagen y la almacenamos en una variable
        self.image = cargar_imagen("images/ball.png",True)
        #esta variable nos sirve para poder interactuar con los 
        #elementos dentro del juego
        self.rect = self.image.get_rect()
        #lugar de inicio por default
        self.rect.centerx = ANCHO/2
        self.rect.centery =  ALTO/2
        #velocidad utilizada para desplazarse en los dos ejes
        self.speed = [0.5,0.5]

    #Este metodo funciona para actualizar en pantalla los elementos de 
    #de nuestro juego
    def actualizar ( self,time,pala ,pala_cpu):
        #actualizando la posicion de la bola en pantalla
        self.rect.centerx += self.speed[0]*time
        self.rect.centery += self.speed[1]*time
        
        #cambiar la posicion de la bola al chocar con las paredes
        if self.rect.left <= 0 or self.rect.right >=ANCHO :
            self.speed[0] = -self.speed[0]
            self.rect.centerx += self.speed[0] * time   
        if self.rect.top <= 0 or self.rect.bottom >= ALTO :
            self.speed[1] = -self.speed[1]
            self.rect.centery += self.speed[1]*time
            
        #cambiar la posicion de la bola al colisionar con alguna de 
        #de las palas
        if pygame.sprite.collide_rect(self,pala) :
            self.speed[0] = -self.speed[0]
            self.rect.centerx += self.speed[0]*time
        if pygame.sprite.collide_rect(self,pala_cpu) :
            self.speed[0] = -self.speed[0]
            self.rect.centerx += self.speed[0]*time

El código anterior, nos muestra de manera sencilla como se mueve de manera autónoma la bola sin necesidad de interferir el usuario. Y finalmente para poder utilizarlos en nuestro juego, volvemos a modificar el método "Game_loop", la modificación es la siguiente:

#metodo que contiene a nuestro "Game Loop"
def game_loop ():
    #Creamos la ventana y la asignamos a una variable
    pantalla = pygame.display.set_mode((ANCHO,ALTO))
    #Le ponemos nombre a nuestra ventana
    pygame.display.set_caption("Remake de pong")
    #cargamos la imagen y la almacenamos en una variable
    fondo = cargar_imagen('images/fondo_pong.png')
    #creamos una instancia de la clase Bola
    bola = Bola()
    #Ahora creamos dos instancias de la clase pala: una para
    #el usuario y otra para el computador
    pala = Pala(30)
    pala_cpu = Pala(ANCHO-30)
    #creamos una instancia de Clock para evitar que nuestro juego 
    #sobrepase una cantidad de frames preestablecidos
    clock = pygame.time.Clock()
    while True:  
        #igual que la variable clock, creamos otra para la limitacion
        #de los frames en pantalla
        time = clock.tick(60)
        #creamos una variable para almacenar las teclas presionadas
        #en cada momento del juego
        keys = pygame.key.get_pressed()
        for eventos in pygame.event.get():
            if eventos.type == QUIT:
                sys.exit(0)
        #actualizamos los datos del juego en cada uno de los ciclos
        #del juego
        bola.actualizar(time,pala,pala_cpu)
        pala.mover(time,keys)
        pala_cpu.ia(time,bola)
        #anadimos la imagen y demas elementos a la pantalla
        pantalla.blit(fondo,(0,0))
        pantalla.blit(bola.image,bola.rect)
        pantalla.blit(pala.image,pala.rect)
        pantalla.blit(pala_cpu.image,pala_cpu.rect)
        #actualizamos la pantalla
        pygame.display.flip()
    return 0

La apariencia resultante es la siguiente:

Con esto ya tenemos jugable nuestro pequeño programa, pero aún falta introducir texto en pantalla para mostrar la puntuación de cada uno de los jugadores y posiblemente introducirle sonido, por lo que hoy terminamos con esto y en el próximo post le enseñaré como introducir el texto en pantalla y el sonido de manera sencilla para que terminemos nuestro remake del Pong. Hasta la próxima :).

Nota: el código que hoy hicimos, así como las imágenes las podrán descargar desde aquí.

No hay comentarios:

Publicar un comentario