SlideShare uma empresa Scribd logo
1 de 26
Baixar para ler offline
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                     CURSO: 1º BACHILLERATO




Sprites
Mario se convierte en nuestro Sprite
Los programas que hemos realizado hasta ahora con PyGame son (relativamente) bastante
elaborados y, a medida que crezca la complejidad, pueden volverse más y más enrevesados.
¡Afortunadamente, PyGame se puede encargar por nosotros de muchas más cosas!
En efecto, hay determinados detalles que hemos implementado por nuestra cuenta y que
PyGame ya incorpora de una manera más simple. Sólo hay que aprenderla. No temas; el
trabajo que has empleado hasta aquí te habrá ayudado a crecer como programador/
programadora.
En particular, y gracias al concepto de programación dirigida a objetos, PyGame crea y
gestiona los sprites de manera nativa. Una vez comprendido, ¡todo se vuelve más sencillo!
En las siguientes páginas, vamos a coger una imagen del famoso Mario de Nintendo y
vamos a hacer que se desplace como en los juegos de plataformas (gracias a Kevin Harris
por un pequeño programa de demostración en el que nos estamos apoyando). De paso
aprenderemos cómo modificar el movimiento para que parezca no lineal, simulando la
gravedad.




¡Vamos allá!




 PÁGINA 1 DE 26
                             
           DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
    
                        CURSO: 1º BACHILLERATO


mario01.py
En este primer paso sólo vamos a mostrar la imagen de Mario como resultado, pero
internamente habremos creado un sprite que luego nos servirá para continuar y ampliarlo
en los siguientes casos. Éste es el código:


 # -*- coding: utf-8 -*-
 #-----------------------------------------------------------------------
 # mario01.py
 # Implemetación de sprites
 #-----------------------------------------------------------------------

 import sys
 import pygame
 from pygame.locals import *

 # Clase MiSprite
 class MiSprite( pygame.sprite.Sprite ):
    # Inicializador de la clase
    def __init__( self, dibujo ):
       # Importante: Primero hay que inicializar la clase Sprite original
       pygame.sprite.Sprite.__init__( self )

       # Almacenar en el sprite la imagen deseada
       self.image = pygame.image.load(dibujo)
       self.image = self.image.convert()

       # Definir el rect del sprite
       self.rect = self.image.get_rect()
       self.rect.topleft = (0, 150)

 # Inicializar PyGame y crear la Surface del juego
 pygame.init()
 visor = pygame.display.set_mode((640, 480))

 # Inicializar el sprite
 sprite = MiSprite("mario.bmp")
 grupo = pygame.sprite.RenderUpdates( sprite )

 # Crear un reloj para controlar la animación
 reloj = pygame.time.Clock()

 # El bucle de la animación
 while 1:
    #Fijar la animación a 60 fps
    reloj.tick(60)

    # Gestionar los eventos
    for evento in pygame.event.get():
       if evento.type == QUIT:
           pygame.quit()




 PÁGINA 2 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
    
                       CURSO: 1º BACHILLERATO



          sys.exit()

    # Actualizar el sprite
    grupo.update()

    # Dibujar la escena
    visor.fill((255,255,255))
    grupo.draw( visor )

    # Mostrar la animación
    pygame.display.update()




Tras la importación de las librerías habituales, lo primero que hacemos en el código
anterior es definir nuestra nueva clase de sprite que deriva de la clase de sprite de
PyGame.


class MiSprite( pygame.sprite.Sprite ):


pygame.sprite.Sprite es la clase de sprite que implementa PyGame de forma nativa. Al
ponerla entre paréntesis le decimos a Pygame que cree la nuestra a partir de aquella.
Recuerda que toda clase debería tener definida la función especial __init__() en la que
pueden ponerse todas aquellas tareas que queremos que se realicen al crearse los sprites.
¡Ojo, algo muy importante! Cuando definamos una clase basada en otra, es muy
conveniente que llamemos a su vez a la función que inicializa la clase original. Eso
se consigue escribiéndolo en primer lugar:

def __init__( self, dibujo ):
     pygame.sprite.Sprite.__init__( self )


Un secreto con respecto al significado de self. Cuando creamos un objeto del tipo de la
clase que estamos definiendo, self representa al objeto mismo. Es un convenio muy
útil pero que al programador primerizo le causa algún que otro dolor de cabeza. Python
está construido de forma que en toda función que se defina dentro de una clase, el
primer argumento debe ser siempre self. Sin embargo, cuando se invoca a estas
funciones, nunca se pone el susodicho self. Python se encarga por sí mismo de
pasárselo a la función y no tienes que ocuparte tú de ello. Acuérdate siempre de esto; en la
definición sí, en el uso no.
A su vez, si quieres definir variables que pertenezcan al objeto para poder utilizarlas
posteriormente, siempre debes definirlas con el como propiedades del objeto self, es decir,
debes definirlas con el self. por delante. En nuestro ejemplo, definimos la variable
self.image para almacenar en ella el dibujo que tendrá nuestro sprite:

      self.image = pygame.image.load(dibujo)


 PÁGINA 3 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
    
                       CURSO: 1º BACHILLERATO

De hecho, self.image es una propiedad que PyGame nos obliga a definir en nuestros
sprites, pues es la que usará automáticamente para dibujarlos en pantalla. Fíjate cómo lo
hemos hecho; en la definición de la función __init__() hemos puesto un segundo
argumento, además de self, dibujo. Allí le pasaremos la imagen cuando creemos el objeto
que representa nuestro sprite de Mario. En la definición de self.image usamos, por lo
tanto, la función de PyGame que ya conocemos para cargarla, pygame.image.load(). A
su vez, también como sabemos, conviene convertir la imagen al formato adecuado para
Pygame, así que la siguiente línea es

      self.image = self.image.convert()

¿Te suena verdad? El resultado de convertir la imagen lo volvemos a almacenar en la
variable self.image. ¡Ya está preparada para ser utilizada!
¿Qué mas cosas hemos puesto en la función __init__() ? Hay otra propiedad de los
sprites que PyGame nos obliga a definir también y es self.rect. Se trata, ni más ni menos,
de una variable de tipo rect que almacena la posición y el tamaño tiene nuestro sprite.

      self.rect = self.image.get_rect()
      self.rect.topleft = (0, 150)


La manera más sencilla de obtener el rect es decirle a Python que lo calcule por sí misma
llamando a la función miembro de una imagen get_rect(). Esta función nos devuelve el
tamaño de la imagen a la que pertenece (en forma de rect). En la siguiente línea lo único
que hacemos es indicar en qué posición va a estar el sprite modificando las propiedades
top y left del rect (consulta la documentación de PyGame). Inicialmente, estará a la
izquierda de la ventana (0) y a 150 pixeles del borde superior.
¡Ya tenemos definido nuestro sprite! Lo siguiente es inicializar PyGame y crear la Surface
donde vamos a mostrar la animación. Optamos por una ventana de 640x480 pixeles, con
las opciones que PyGame toma por defecto.

pygame.init()
visor = pygame.display.set_mode((640, 480))


Ha llegado el momento importante; vamos a crear a Mario. Crear un sprite es un
proceso que, comúnmente, requiere dos pasos. Primero hay que crear al propio
sprite. Y segundo hay que agruparlo. ¿Qué quiere decir esto? De cara a manejar
múltiples sprites, nos interesa tenerlos clasificados (el protagonista, los malos, la
comida...). PyGame nos dará posteriormente herramientas para trabajar con todos ellos a
la vez o por separado, gestionar sus colisiones, etc. Esto hay que hacerlo siempre, incluso
cuando, como ahora, tenemos un sólo sprite. Veamos:

sprite = MiSprite("mario.bmp")
grupo = pygame.sprite.RenderUpdates( sprite )


Hemos creado dos variables. La primera, sprite, contiene nuestro sprite de Mario. La
segunda, grupo, contiene el grupo al que pertenece nuestro sprite.
¿Cómo lo hemos hecho? Para empezar, hemos invocado el nombre de la clase del sprite
pasándole como argumento el nombre del archivo que contiene la imagen que vamos a
 PÁGINA 4 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                       CURSO: 1º BACHILLERATO

usar. Fíjate en la definición de la clase; allí verás que la función __init__() la hemos
puesto con dos parámetros, self (que recuerda que se ignora cuando se llama a la función)
y otra más que luego usamos en la definición para indicar la imagen del sprite.
Para añadir un sprite a un grupo usamos pygame.sprite.RenderUpdates(); esta
función nos crea un grupo de sprites al que añade el que le pasemos como argumento.
El grupo, como hemos dicho, lo almacenamos en una variable que hemos llamado (qué
imaginación) grupo. Dicho sea de paso, si tuviéramos otro sprite y quisiéramos añadirlo a
este grupo, bastaría que escribiéramos grupo.add(nombre_de_otro_sprite). ¡Fácil!
Lo siguiente es algo que va a hacer mucho más simple lo que hasta ahora hemos hecho más
complicado; controlar la velocidad de la animación. En los tutoriales anteriores lo
hemos hecho a mano, mirando el tiempo que pasaba y ajustando la diferencia hasta que se
conseguía el tiempo requerido. Afortunadamente, Python se puede encargar
automáticamente de eso por ti. Para ello necesitamos crear un objeto especial:

reloj = pygame.time.Clock()

pygame.time.Clock() nos devuelve un objeto que almacenamos en la variable reloj y
que se encargará de controlar los fotogramas por segundo a los que se va mostrar la
animación. Lo podemos ver al comienzo del bucle habitual:

while 1:
  #Fijar la animación a 60 fps
  reloj.tick(60)


¡Qué sencillo resulta ahora! Como quiero que la animación se reproduzca a 60 fotogramas
por segundo y no más rápido, basta con que lo indique usando la función tick() del objeto
reloj. Python, por sí mismo, se encargará de esperar lo suficiente (si hace falta) para
conseguirlo...
Con la seguridad de que lo tenemos todo controlado (incluido el típico código de eventos
que solemos usar para salir del programa), podemos pasar a la tarea de dibujar en pantalla
el fotograma. Una vez conocido el sistema, es muy sencillo. Piensa que, en cada pasada
del bucle, lo que deseas hacer es mirar todos los sprites que tengas, ver donde tienes que
ponerlos, borrarlos de donde estaban antes y dibujarlos en sus nuevas posiciones. Si te
fijas, es precisamente eso lo que hemos hecho en el código:

 # Actualizar el sprite
  grupo.update()

   # Dibujar la escena
   visor.fill((255,255,255))
   grupo.draw( visor )

   # Mostrar la animación
   pygame.display.update()


Aquí podemos ver la utilidad del concepto de grupo de PyGame. Para decirle al grupo
que actualice las posiciones (esto es, que averigüe cuáles deben ser las nuevas
posiciones) de todos sus sprites basta usar su función miembro update(). Y para decirle
 PÁGINA 5 DE 26
                             
            DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                       CURSO: 1º BACHILLERATO

que los dibuje en esas posiciones usamos draw() pasándole como argumento la surface
en la que ha de hacerse (nuestro visor). Finalmente, como siempre en PyGame, volcamos
toda esa información en pantalla para que la muestre con pygame.display.update().
Te puedes preguntar ¿y cómo sabe PyGame, cuando llamo a grupo.update() dónde están
las nuevas posiciones de los sprites? En realidad, grupo.update() lo que hace es llamar a
las funciones update() de todos los sprites que pertencen al grupo. Como nosotros no
hemos definido esa función en MiSprite, PyGame no hace nada y deja a Mario siempre en
la misma posición. Ejecuta el programa:




Una vez que comprendas el proceso, verás que es sencillo y potente. Prueba a eliminar los
comentarios; el código que resulta es bastante breve y fácil de entender




 PÁGINA 6 DE 26
                             
            DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario02.py
La ventaja de utilizar la programación dirigida a objetos que incorpora PyGame es
que modificar el comportamiento de los sprites es muy sencillo. Vamos a darle movimiento
a Mario. Nada más simple:




    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario02.py
    # Movimiento sencillo
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (0, 150)

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(1,0)

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))

    # Inicializar el sprite
    sprite = MiSprite("mario.bmp")
    grupo = pygame.sprite.RenderUpdates( sprite )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación
    while 1:




 PÁGINA 7 DE 26
                               
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                      CURSO: 1º BACHILLERATO



       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()




¡Extremadamente sencillo! ¿Recuerdas que, en cada fotograma, grupo.update() llama a
la función update() de cada sprite para saber dónde debe dibujarlo? Bueno, pues
simplemente debemos definir esa función dentro de nuestra clase para tener la tarea
hecha. Esto es lo único que hemos añadido al código:

   def update(self):
     # Modificar la posición del sprite
     self.rect.move_ip(1,0)



De paso, usamos otra función incorporada, move_ip(), que también hace las cosas más
sencillas. En lugar de modificar a mano las coordenadas de self.rect, el rectángulo que
define la posición y el tamaño del sprite, move_ip() toma de argumento dos valores que
indican cuánto hay que desplazar el rect. En nuestro ejemplo, este desplazamiento es de 1
pixel hacia la derecha y 0 pixeles hacia abajo (es decir, no se desplaza en dirección
vertical).
Terminado. Si ejecutas el programa verás a Mario desplazándose lentamente por la
pantalla; exactamente a 60 pixeles por segundo (1 pixel en cada fotograma, 60 fotogramas
por segundo).




 PÁGINA 8 DE 26
                             
            DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario03.py
Implementar el rebote es igual de sencillo:


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario03.py
    # Rebote
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (0, 150)

          # Definir las velocidad
          self.dx = 1

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,0)
         # Comprobar si hay que cambiar el movimiento
          if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))

    # Inicializar el sprite
    sprite = MiSprite("mario.bmp")
    grupo = pygame.sprite.RenderUpdates( sprite )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación




 PÁGINA 9 DE 26
                               
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                       CURSO: 1º BACHILLERATO



    while 1:
      #Fijar la animación a 60 fps
      reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()




La forma de conseguir el rebote ya la conocemos; ver cuando se llega al borde de la ventana
y cambiar el sentido del movimiento cambiando de signo la cantidad que sumas a la
posición. Lógicamente, para poder cambiar ese signo, necesitamos almacenar la cantidad
que sumamos a la posición en una variable. Como es un movimiento en el eje horizontal,
llamemos a esa variable dx. Como es una variable que ha de pertenecer al sprite, vamos
a poner su definición en la función __init__() de la clase y, por lo tanto, deberemos
añadirle al nombre el ya conocido self:

     # Definir las velocidad
     self.dx = 1


Bien. Una vez hecho esto, implementar el rebote de Mario requiere modificar la definición
de la función update() del sprite:

   def update(self):
     # Modificar la posición del sprite
     self.rect.move_ip(self.dx,0)
     # Comprobar si hay que cambiar el movimiento
     if self.rect.left < 0 or self.rect.right > 640:
         self.dx = -self.dx

En efecto, primero movemos el sprite la cantidad deseada (ahora es self.dx) y luego
miramos si se ha llegado a uno de los extremos de la pantalla, en cuyo caso cambiamos el
movimiento cambiando el signo de self.dx.
¿Ves qué sencillo?




 PÁGINA 10 DE 26
                            
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario04.py
Un nuevo paso. Esta vez, al igual que hacíamos con Guy, vamos a invertir la imagen del
sprite cuando éste rebote. Éste es el código:


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario04.py
    # Rebote invirtiendo el sprite
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (0, 150)

          # Definir la velocidad
          self.dx = 1

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,0)
         # Comprobar si hay que cambiar el movimiento
         if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx
             self.image = pygame.transform.flip( self.image, True, False )

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))

    # Inicializar el sprite
    sprite = MiSprite("mario.bmp")
    grupo = pygame.sprite.RenderUpdates( sprite )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()




 PÁGINA 11 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                       CURSO: 1º BACHILLERATO



    # El bucle de la animación
    while 1:
       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()




¿Puedes creer que sea algo tan simple? Pues sí: en el mismo lugar del código donde
miramos si el sprite ha llegado al borde (y cambiamos la dirección del movimiento en caso
afirmativo), lo único que hacemos es transformar la imagen de Mario por su reflejo
horizontal

      if self.rect.left < 0 or self.rect.right > 640:
          self.dx = -self.dx
          self.image = pygame.transform.flip( self.image, True, False )


De nuevo, igual que hicimos con Guy, la función pygame.transform.flip() nos permite
hacer esa inversión de la imagen. El resultado, lo volvemos a almacenar en self.image que
contiene el aspecto de nuestro sprite y, a partir de entonces, nuestro Mario estará
mirando en su movimiento hacia el otro lado. ¡Perfecto!
Espero que, en este punto, comprendas las ventajas de la programación dirigida a
objetos y del concepto de Sprite de PyGame; todo su comportamiento lo incluimos en la
definición de la clase y cuando usemos un objeto de ese tipo, automáticamente se
comportará como tal. Ello hace que los programas sean mucho más fácilmente
modificables y ampliables, como estamos viendo.




 PÁGINA 12 DE 26
                            
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
             CURSO: 1º BACHILLERATO




PÁGINA 13 DE 26
                            
   DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario05.py
Implementar el movimiento en la dirección vertical, incluido el rebote correspondiente, te
debería resultar ahora bastante fácil:


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario05.py
    # Implementando el movimiento vertical
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (0, 150)

          # Definir las velocidades
          self.dx = 1
          self.dy = 1

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,self.dy)
         # Comprobar si hay que cambiar el movimiento
         if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx
             self.image = pygame.transform.flip( self.image, True, False )
         if self.rect.top < 0 or self.rect.bottom > 480:
             self.dy = -self.dy

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))

    # Inicializar el sprite
    sprite = MiSprite("mario.bmp")
    grupo = pygame.sprite.RenderUpdates( sprite )




 PÁGINA 14 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                     CURSO: 1º BACHILLERATO



    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación
    while 1:
       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()




¿Hace falta explicar algo? Sólo hemos añadido en __init__() la nueva velocidad vertical
self.dy y en update() la hemos añadido al movimiento y a la comprobación del rebote.




 PÁGINA 15 DE 26
                            
           DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario06.py
Hasta ahora sólo hemos hecho movimientos rectilíneos y uniformes. ¿Qué tal simular algo
más real, como una caída con gravedad?


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario06.py
    # Simular la gravedad
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (0, 150)

          # Definir las velocidades
          self.dx = 1
          self.dy = 1

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,self.dy)
         # Comprobar si hay que cambiar el movimiento
         if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx
             self.image = pygame.transform.flip( self.image, True, False )
         if self.rect.top < 0 or self.rect.bottom > 480:
             self.dy = -self.dy
         # Simular la gravedad sumando una cantidad a la velocidad vertical
         self.dy = self.dy + 0.5

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))

    # Inicializar el sprite




 PÁGINA 16 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
   
                         CURSO: 1º BACHILLERATO



    sprite = MiSprite("mario.bmp")
    grupo = pygame.sprite.RenderUpdates( sprite )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación
    while 1:
       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()



¿Te podías imaginar que era tan sencillo? Lo único que hemos hecho ha sido añadir en la
función update() la siguiente línea de código:

      self.dy = self.dy + 0.5

La explicación es muy simple. La gravedad lo único que hace es empujarnos hacia abajo de
manera constante. Y la manera de hacerlo en la función update() es, por lo tanto, sumar
una cantidad constante a la velocidad en el eje vertical. Fíjate que tiene precisamente el
efecto deseado; cuando el sprite va hacia arriba (self.dy es entonces negativa) al sumarle
0.5 lo que hace es frenarse y cuando va hacia abajo (self.dy positiva) acelerarse.
Por supuesto, sin más que variar ese 0.5 conseguimos una gravedad más o menos intensa.
¡Ejecuta el programa! Veras como el rebote es ahora más divertido...
No obstante, hay dos detalles que debemos cuidar. El primero es que en mucho juegos tipo
plataforma, no queremos que el protagonista se frene y que rebote siempre a la misma
altura, no que se vaya frenando. Lo segundo es que tenemos un pequeño bug; si
esperamos lo suficiente, veremos como Mario... ¡termina por atravesar los bordes de la
ventana!
En el próximo paso veremos cómo solucionar esto.




 PÁGINA 17 DE 26
                            
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario07.py
El que el rebote sea siempre a la misma altura y el que Mario termine atravesando el suelo
de la ventana pueden solucionarse con una sola línea:


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario07.py
    # Movimiento de plataforma
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (0, 150)

          # Definir las velocidades
          self.dx = 5.0
          self.dy = 1.0

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,self.dy)
         # Comprobar si hay que cambiar el movimiento
         if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx
             self.image = pygame.transform.flip( self.image, True, False )
             self.rect.move_ip(self.dx,self.dy)
         if self.rect.top < 0 or self.rect.bottom > 480:
             self.dy = -self.dy
             self.rect.move_ip(self.dx,self.dy)
         # Simular la gravedad sumando una cantidad a la velocidad vertical
         self.dy = self.dy + 0.5

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))




 PÁGINA 18 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO



    # Inicializar el sprite
    sprite = MiSprite("mario.bmp")
    grupo = pygame.sprite.RenderUpdates( sprite )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación
    while 1:
       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()




En efecto, basta darle al sprite un pequeño empujoncito extra en el momento en el que
llega al borde. Eso nos deja el movimiento con el mismo valor que justo antes de
producirse el rebote, con lo que llegará hasta la misma altura al subir (observa que la altura
a la que llega Mario es como un quesito y ese 0.5 que añadimos a la velocidad como un
ratón; va mordiéndole y quitando un trozo tras otro hasta que lo termina, de ahí que el
rebote vaya, de partida, disminuyendo poco a poco) y no se producirán efectos extraños en
las paredes.

   if self.rect.left < 0 or self.rect.right > 640:
          self.dx = -self.dx
          self.image = pygame.transform.flip( self.image, True, False )
          self.rect.move_ip(self.dx,self.dy)
   if self.rect.top < 0 or self.rect.bottom > 480:
          self.dy = -self.dy
          self.rect.move_ip(self.dx,self.dy)


Por cierto, si necesitáramos solucionar el tema de atravesar el suelo por su cuenta,
tampoco sería complicado. ¿Te imaginas cómo? Fácil; antes de cambiar la posición del
sprite con move_ip() deberías comprobar si ya está en el suelo, en cuyo caso deberías
poner el valor de self.dy a cero para que dejara de bajar. (Pregunta: ¿Cómo saber si los
pies de Mario están en el borde de la ventana? Respuesta: con el atributo bottom que
tiene todo objeto de tipo rect)
 PÁGINA 19 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario08.py
Ya que estamos trabajando con sprites. ¿Por qué limitarnos a un sólo Mario? Traigamos a
su hermano gemelo a la fiesta...


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario08.py
    # Varios sprites
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo, posX, posY ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (posX, posY)

          # Definir las velocidades
          self.dx = 5.0
          self.dy = 1.0

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,self.dy)
         # Comprobar si hay que cambiar el movimiento
         if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx
             self.image = pygame.transform.flip( self.image, True, False )
             self.rect.move_ip(self.dx,self.dy)
         if self.rect.top < 0 or self.rect.bottom > 480:
             self.dy = -self.dy
             self.rect.move_ip(self.dx,self.dy)
         # Simular la gravedad sumando una cantidad a la velocidad vertical
         self.dy = self.dy + 0.5

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()
    visor = pygame.display.set_mode((640, 480))




 PÁGINA 20 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
       
                        CURSO: 1º BACHILLERATO



    # Inicializar los sprites
    sprite = MiSprite("mario.bmp", 0, 150)
    grupo = pygame.sprite.RenderUpdates( sprite )
    sprite2 = MiSprite("mario.bmp", 210, 50)
    grupo.add( sprite2 )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación
    while 1:
       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Actualizar el sprite
       grupo.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )

       # Mostrar la animación
       pygame.display.update()




Para empezar, hemos modificado ligeramente la definición de nuestro tipo de sprite ya que
si no todos los sprites que creemos de este tipo comenzarán en el mismo sitio (y por tanto
sólo veríamos uno). Esto es fácil de solucionar; ponemos dos parámetros más en la función
miembro __init__() que inicializa la clase.

  def __init__( self, dibujo, posX, posY ):

Los parámetros posX y posY se encargarán de situar en su posición inicial al sprite. Ello
quiere decir que hay que modificar una línea más de esta función:

      self.rect.topleft = (posX, posY)


para que así, en efecto, el sprite se posicione allí al principio.
Lo último que queda es, simplemente, crear los sprites:

sprite = MiSprite("mario.bmp", 0, 150)
grupo = pygame.sprite.RenderUpdates( sprite )
sprite2 = MiSprite("mario.bmp", 210, 50)
grupo.add( sprite2 )

 PÁGINA 21 DE 26
                                
              DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO

Respecto del primer Mario, poco que decir. Lo único que hemos modificado es que, ahora,
en la creación del sprite hay que indicar la posición en la que lo queremos. Con el segundo
sprite hacemos lo mismo (con otra posición distinta) y, como ya está creado el grupo de
sprites, lo añadimos con la función miembro add().




Dos cosas podrás notar cuando ejecutes el programa. La primera es que, como la imagen
de Mario no tiene transparencias, cuando se superponen los dos gemelos se ve el cuadrado
blanco que envuelve a la imagen. La segunda es que cada sprite ignora al otro. ¿Cómo
podríamos gestionar la colisión entre ambos de manera que, por ejemplo, rebotaran?
El problema de la transparencia, en este caso, es muy fácil de solucionar ya que sólo hay
que decirle al sprite qué color ha de tomar como transparente (para no dibujarlo). Eso se
consigue añadiendo una sola línea el la función __init__() del sprite:

      self.image.set_colorkey((255,255,255))

La función set_colorkey() es una función miembro de cualquier surface (y una imagen
es a su vez una surface) que toma un argumento que no es si no el color que se usará
como transparente. Si la añades y lanzas el programa, verás que ya no aparece ese
cuadrado blanco tan molesto alrededor de Mario.
Respecto de la colisión de los sprites... tendremos que pasar a la última versión del
programa.




 PÁGINA 22 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


mario09.py
Hay varias formas de abordar el tema. La que viene a continuación es sólo una de las más
sencillas:


    # -*- coding: utf-8 -*-
    #-------------------------------------------------------------------
    # mario09.py
    # Sprites con colisión
    #-------------------------------------------------------------------

    import sys
    import pygame
    from pygame.locals import *

    # Clase MiSprite
    class MiSprite( pygame.sprite.Sprite ):
       # Inicializador de la clase
       def __init__( self, dibujo, posX, posY ):
          # Importante: Primero hay que inicializar la clase Sprite original
          pygame.sprite.Sprite.__init__( self )

          # Almacenar en el sprite la imagen deseada
          self.image = pygame.image.load(dibujo)
          self.image = self.image.convert()
          self.image.set_colorkey((255,255,255))

          # Definir el rect del sprite
          self.rect = self.image.get_rect()
          self.rect.topleft = (posX, posY)

          # Definir las velocidades
          self.dx = 5.0
          self.dy = 1.0

       def update(self):
         # Modificar la posición del sprite
         self.rect.move_ip(self.dx,self.dy)
         # Comprobar si hay que cambiar el movimiento
         if self.rect.left < 0 or self.rect.right > 640:
             self.dx = -self.dx
             self.image = pygame.transform.flip( self.image, True, False )
             self.rect.move_ip(self.dx,self.dy)
         if self.rect.top < 0 or self.rect.bottom > 480:
             self.dy = -self.dy
             self.rect.move_ip(self.dx,self.dy)
         # Simular la gravedad sumando una cantidad a la velocidad vertical
         self.dy = self.dy + 0.5

    # Inicializar PyGame y crear la Surface del juego
    pygame.init()




 PÁGINA 23 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
    
                       CURSO: 1º BACHILLERATO



    visor = pygame.display.set_mode((640, 480))

    # Inicializar los sprites
    sprite = MiSprite("mario.bmp", 0, 150)
    grupo = pygame.sprite.RenderUpdates( sprite )
    sprite2 = MiSprite("mario.bmp", 210, 50)
    grupo2 = pygame.sprite.RenderUpdates( sprite2 )

    # Crear un reloj para controlar la animación
    reloj = pygame.time.Clock()

    # El bucle de la animación
    while 1:
       #Fijar la animación a 60 fps
       reloj.tick(60)

       # Gestionar los eventos
       for evento in pygame.event.get():
          if evento.type == QUIT:
              pygame.quit()
              sys.exit()

       # Mira si hay alguna colisión:
       if pygame.sprite.spritecollideany(sprite, grupo2):
          sprite.dx = -sprite.dx
          sprite.dy = -sprite.dy
          sprite2.dx = -sprite2.dx
          sprite2.dy = -sprite2.dy

       # Actualizar el sprite
       grupo.update()
       grupo2.update()

       # Dibujar la escena
       visor.fill((255,255,255))
       grupo.draw( visor )
       grupo2.draw( visor )

       # Mostrar la animación
       pygame.display.update()




Lo primero es una advertencia: como cualquier programador sabe, los documentos de
referencia (en los que se incluyen las librerías, objetos e instrucciones disponibles en el
lenguaje) son un compañero inseparable en la aventura de programar. ¿No tienes
cerca la referencia de Pygame? Cógela ahora mismo. Piensa que te nombramos unas pocas
funciones u objetos pero hay muchas más. Y muchas más opciones.
Lo segundo es hacerte notar que hemos añadido la línea a la que nos referíamos al final del
capítulo anterior, el código que consigue que el color blanco (255,255,255) se tome como
transparente y no se dibuje.


 PÁGINA 24 DE 26
                             
            DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
    
                       CURSO: 1º BACHILLERATO

Bien, vamos al tema de la detección de colisiones. PyGame incorpora muchas
funciones que gestionan los posibles choques entre sprites y/o grupos. ¡Mira el documento
de Referencia de PyGame! Como notarás enseguida, una de las maneras más cómodas
es usar la función pygame.sprite.spritecollideany(). Fíjate qué pone en la referencia:




   spritecollideany
   Consulta simple para ver si un sprite colisiona con algún otro en el grupo.

   pygame.sprite.spritecollideany(sprite, group): return bool

   Consulta si el sprite dado colisiona con algún sprite en el grupo. La intersección se
   determina comparando el atributo Sprite.rect de cada sprite.

   Esta prueba de colisión puede ser mas rápida que

   pygame.sprite.spritecollideany()

   dado que tiene menos trabajo para hacer. Retornará al encontrar la primer colisión.




Lo que nos interesa son dos cosas; la función toma dos argumentos (un Sprite y un
Grupo) y devuelve un Booleano (True o False). En definitiva, lo que hace es mirar si el
sprite que le pasamos a la función colisiona con algún sprite que pertenezca al
grupo que también le pasamos, devolviéndonos True o False en consecuencia. Esto nos
viene muy bien pues solo tenemos dos sprites. En programas más complejos, con muchos
sprites, necesitaríamos otras funciones distintas que nos dijeran a su vez cuáles son los
sprites que han colisionado, etc.
He aquí otro punto importante; como suele mirarse la colisión de sprites y grupos,
conviene tener separados los sprites que queremos mirar si colisionan en diferentes
grupos. Típicamente, por ejemplo, tendríamos un grupo para las naves de los enemigos y
otro grupo para los rayos láser. O, en el juego del Pong, un grupo para las raquetas y otro
para la pelota. Ésa es la razón por la que hemos puesto lo siguiente:

 sprite = MiSprite("mario.bmp", 0, 150)
 grupo = pygame.sprite.RenderUpdates( sprite )
 sprite2 = MiSprite("mario.bmp", 210, 50)
 grupo2 = pygame.sprite.RenderUpdates( sprite2 )

En el capítulo anterior añadíamos el sprite sprite2 al grupo grupo en el que estaba el
sprite sprite. Como ahora queremos mirar cuándo chocan, definimos un nuevo grupo,
grupo2. ¡Ya los tenemos separados!
Lo siguiente es implementar la colisión. Como ya hemos visto más arriba la sintaxis de la
función pygame.sprite.spritecollideany(), no debería ser difícil de entender:


 PÁGINA 25 DE 26
                             
             DURACIÓN: PERÍODOS DE DOS CLASES
ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
     
                       CURSO: 1º BACHILLERATO


   # Mira si hay alguna colisión:
   if pygame.sprite.spritecollideany(sprite, grupo2):
      sprite.dx = -sprite.dx
      sprite.dy = -sprite.dy
      sprite2.dx = -sprite2.dx
      sprite2.dy = -sprite2.dy

En el código anterior miramos si el sprite sprite ha chocado con algún miembro del grupo
grupo2 (vamos, con su hermano gemelo que es el único sprite de ese grupo). En caso
afirmativo, pygame.sprite.spritecollideany() devuelve True y, por tanto, se ejecuta el
interior del bloque if. ¿Qué hacemos allí? Análogamente al rebote en los bordes de la
ventana, cambiamos las direcciones de movimiento de los dos sprites. ¡Rebote conseguido!
Sólo queda añadir la parte de código que tiene en cuenta que ahora no hay sólo un grupo
para actualizar y dibujar en pantalla. Así que, en los sitios correspondientes, hay que
colocar primero

   grupo2.update()


y después

   grupo2.draw( visor )


Ejecuta ahora el programa... ¡Genial!




Por cierto; cuando rebotan los dos marios, el uno contra el otro, no invierten su dibujo. Y si
dejas que pase el tiempo suficiente, pueden llegar a engancharse... ¿Sabrías solucionarlo?
Ya puestos, ¿sabrías hacer que comiencen desde una posición aleatoria? ¿Y que salgan, no
dos, si no muchos marios, por ejemplo cada vez que se haga click con el ratón?
Ante nosotros se extiende un campo de creatividad ilimitado...


 PÁGINA 26 DE 26
                              
             DURACIÓN: PERÍODOS DE DOS CLASES

Mais conteúdo relacionado

Mais procurados

Maintainable CSS
Maintainable CSSMaintainable CSS
Maintainable CSSStephen Hay
 
Manage your calls with CallKit
Manage your calls with CallKitManage your calls with CallKit
Manage your calls with CallKitGuillaume Berthier
 
MANEJO Y REPRODUCCION PORCINOS
MANEJO Y REPRODUCCION PORCINOSMANEJO Y REPRODUCCION PORCINOS
MANEJO Y REPRODUCCION PORCINOSkristell charlene
 
Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500
Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500
Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500Mv Robell Masís
 

Mais procurados (13)

Sling Models Overview
Sling Models OverviewSling Models Overview
Sling Models Overview
 
Maintainable CSS
Maintainable CSSMaintainable CSS
Maintainable CSS
 
Mycoplasmosis
MycoplasmosisMycoplasmosis
Mycoplasmosis
 
Aerosaculitis aviar
Aerosaculitis aviarAerosaculitis aviar
Aerosaculitis aviar
 
Manage your calls with CallKit
Manage your calls with CallKitManage your calls with CallKit
Manage your calls with CallKit
 
MANEJO Y REPRODUCCION PORCINOS
MANEJO Y REPRODUCCION PORCINOSMANEJO Y REPRODUCCION PORCINOS
MANEJO Y REPRODUCCION PORCINOS
 
CODORNIZ.pptx
CODORNIZ.pptxCODORNIZ.pptx
CODORNIZ.pptx
 
Advanced Json
Advanced JsonAdvanced Json
Advanced Json
 
Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500
Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500
Comportamiento Productivo y Económico de Pollos de Engorde de la Línea COBB 500
 
Coriza infecciosa
Coriza infecciosaCoriza infecciosa
Coriza infecciosa
 
Coriza aviar
Coriza aviarCoriza aviar
Coriza aviar
 
Wpf Introduction
Wpf IntroductionWpf Introduction
Wpf Introduction
 
Salmonella Aviar
Salmonella AviarSalmonella Aviar
Salmonella Aviar
 

Destaque

Programación con Pygame III
Programación con Pygame IIIProgramación con Pygame III
Programación con Pygame IIIFernando Salamero
 
Programación con Pygame (II)
Programación con Pygame (II)Programación con Pygame (II)
Programación con Pygame (II)Fernando Salamero
 
Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014
Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014
Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014Fernando Salamero
 
(Sin anotaciones) - En busca de la Física
(Sin anotaciones) - En busca de la Física(Sin anotaciones) - En busca de la Física
(Sin anotaciones) - En busca de la FísicaFernando Salamero
 
Programación de Videojuegos con Python y Pilas (III)
Programación de Videojuegos con Python y Pilas (III)Programación de Videojuegos con Python y Pilas (III)
Programación de Videojuegos con Python y Pilas (III)Fernando Salamero
 
Curso Programacion de Juego Introducion IA
Curso Programacion de Juego Introducion IACurso Programacion de Juego Introducion IA
Curso Programacion de Juego Introducion IARicardo Daniel Quiroga
 
Programación de Videojuegos con Python y Pilas (I)
Programación de Videojuegos con Python y Pilas (I)Programación de Videojuegos con Python y Pilas (I)
Programación de Videojuegos con Python y Pilas (I)Fernando Salamero
 
Programación de Videojuegos con Python y Pilas (II)
Programación de Videojuegos con Python y Pilas (II)Programación de Videojuegos con Python y Pilas (II)
Programación de Videojuegos con Python y Pilas (II)Fernando Salamero
 

Destaque (20)

Programación con Pygame III
Programación con Pygame IIIProgramación con Pygame III
Programación con Pygame III
 
Programación con Pygame VI
Programación con Pygame VIProgramación con Pygame VI
Programación con Pygame VI
 
Intro PygameCapitulo 3
Intro PygameCapitulo 3Intro PygameCapitulo 3
Intro PygameCapitulo 3
 
Intro Pygame Capitulo 2
Intro Pygame Capitulo 2Intro Pygame Capitulo 2
Intro Pygame Capitulo 2
 
Intro pygamev2
Intro pygamev2Intro pygamev2
Intro pygamev2
 
Python básico II
Python básico IIPython básico II
Python básico II
 
Intro Pygame Capitulo 6
Intro Pygame Capitulo 6Intro Pygame Capitulo 6
Intro Pygame Capitulo 6
 
Pythonic Math
Pythonic MathPythonic Math
Pythonic Math
 
Intro PyGame Capitulo 0
Intro PyGame Capitulo 0Intro PyGame Capitulo 0
Intro PyGame Capitulo 0
 
Programación con Pygame (II)
Programación con Pygame (II)Programación con Pygame (II)
Programación con Pygame (II)
 
Intro PyGame Capitulo 1
Intro PyGame Capitulo 1Intro PyGame Capitulo 1
Intro PyGame Capitulo 1
 
Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014
Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014
Taller de Pilas Engine, un motor de juegos en Python - PyConES 2014
 
(Sin anotaciones) - En busca de la Física
(Sin anotaciones) - En busca de la Física(Sin anotaciones) - En busca de la Física
(Sin anotaciones) - En busca de la Física
 
Programación de Videojuegos con Python y Pilas (III)
Programación de Videojuegos con Python y Pilas (III)Programación de Videojuegos con Python y Pilas (III)
Programación de Videojuegos con Python y Pilas (III)
 
Curso Programacion de Juego Introducion IA
Curso Programacion de Juego Introducion IACurso Programacion de Juego Introducion IA
Curso Programacion de Juego Introducion IA
 
Programación de Videojuegos con Python y Pilas (I)
Programación de Videojuegos con Python y Pilas (I)Programación de Videojuegos con Python y Pilas (I)
Programación de Videojuegos con Python y Pilas (I)
 
Capitulo 4
Capitulo 4Capitulo 4
Capitulo 4
 
Intro PyGame Capitulo 5
Intro PyGame Capitulo 5Intro PyGame Capitulo 5
Intro PyGame Capitulo 5
 
Programación de Videojuegos con Python y Pilas (II)
Programación de Videojuegos con Python y Pilas (II)Programación de Videojuegos con Python y Pilas (II)
Programación de Videojuegos con Python y Pilas (II)
 
Programación con Pygame I
Programación con Pygame IProgramación con Pygame I
Programación con Pygame I
 

Semelhante a Programación con Pygame IV

Programación de Videojuegos con Python y Pilas (VII)
Programación de Videojuegos con Python y Pilas (VII)Programación de Videojuegos con Python y Pilas (VII)
Programación de Videojuegos con Python y Pilas (VII)Fernando Salamero
 
Xna game studio presentación 02
Xna game studio   presentación 02Xna game studio   presentación 02
Xna game studio presentación 02Juan Cardona
 
Programación con Pygame VIII
Programación con Pygame VIIIProgramación con Pygame VIII
Programación con Pygame VIIIFernando Salamero
 
Programación de Videojuegos con Python y Pilas (IX)
Programación de Videojuegos con Python y Pilas (IX)Programación de Videojuegos con Python y Pilas (IX)
Programación de Videojuegos con Python y Pilas (IX)Fernando Salamero
 
Como instalar Python y librerias
Como instalar Python y libreriasComo instalar Python y librerias
Como instalar Python y libreriasDaniel Iba
 
Programación de Videojuegos con Python y Pilas (V)
Programación de Videojuegos con Python y Pilas (V)Programación de Videojuegos con Python y Pilas (V)
Programación de Videojuegos con Python y Pilas (V)Fernando Salamero
 
Codemotion 2014 - Introducción a Unity
Codemotion 2014 - Introducción a UnityCodemotion 2014 - Introducción a Unity
Codemotion 2014 - Introducción a UnityMiguelitoCupra
 
Programación de Videojuegos con Python y Pilas (VIII)
Programación de Videojuegos con Python y Pilas (VIII)Programación de Videojuegos con Python y Pilas (VIII)
Programación de Videojuegos con Python y Pilas (VIII)Fernando Salamero
 
Que es action scrip 3
Que es  action scrip 3Que es  action scrip 3
Que es action scrip 3Harolsmr1103
 
Que es action scrip 3
Que es  action scrip 3Que es  action scrip 3
Que es action scrip 3Harolsmr1103
 
Que es action scrip 3
Que es  action scrip 3Que es  action scrip 3
Que es action scrip 3Harolsmr1103
 
Actionscrip linakrdona n2
Actionscrip linakrdona n2Actionscrip linakrdona n2
Actionscrip linakrdona n2LinaCtriana
 
2. tutorial unity3d-disparo
2.  tutorial unity3d-disparo2.  tutorial unity3d-disparo
2. tutorial unity3d-disparoVictor Aravena
 
2. tutorial unity3d-disparo
2.  tutorial unity3d-disparo2.  tutorial unity3d-disparo
2. tutorial unity3d-disparoVictor Aravena
 
Agregar una imagen
Agregar una imagenAgregar una imagen
Agregar una imagenlourdes9898
 
Jowin Rojas Venecia IED
Jowin Rojas Venecia IEDJowin Rojas Venecia IED
Jowin Rojas Venecia IEDdeluxefalen
 

Semelhante a Programación con Pygame IV (20)

Programación de Videojuegos con Python y Pilas (VII)
Programación de Videojuegos con Python y Pilas (VII)Programación de Videojuegos con Python y Pilas (VII)
Programación de Videojuegos con Python y Pilas (VII)
 
Xna game studio presentación 02
Xna game studio   presentación 02Xna game studio   presentación 02
Xna game studio presentación 02
 
Programación con Pygame VIII
Programación con Pygame VIIIProgramación con Pygame VIII
Programación con Pygame VIII
 
Programación con Pygame V
Programación con Pygame VProgramación con Pygame V
Programación con Pygame V
 
Programación con Pygame IX
Programación con Pygame IXProgramación con Pygame IX
Programación con Pygame IX
 
Programación de Videojuegos con Python y Pilas (IX)
Programación de Videojuegos con Python y Pilas (IX)Programación de Videojuegos con Python y Pilas (IX)
Programación de Videojuegos con Python y Pilas (IX)
 
Como instalar Python y librerias
Como instalar Python y libreriasComo instalar Python y librerias
Como instalar Python y librerias
 
Programación de Videojuegos con Python y Pilas (V)
Programación de Videojuegos con Python y Pilas (V)Programación de Videojuegos con Python y Pilas (V)
Programación de Videojuegos con Python y Pilas (V)
 
Codemotion 2014 - Introducción a Unity
Codemotion 2014 - Introducción a UnityCodemotion 2014 - Introducción a Unity
Codemotion 2014 - Introducción a Unity
 
Programación de Videojuegos con Python y Pilas (VIII)
Programación de Videojuegos con Python y Pilas (VIII)Programación de Videojuegos con Python y Pilas (VIII)
Programación de Videojuegos con Python y Pilas (VIII)
 
Que es action scrip 3
Que es  action scrip 3Que es  action scrip 3
Que es action scrip 3
 
Que es action scrip 3
Que es  action scrip 3Que es  action scrip 3
Que es action scrip 3
 
Que es action scrip 3
Que es  action scrip 3Que es  action scrip 3
Que es action scrip 3
 
Clase2
Clase2Clase2
Clase2
 
Actionscrip linakrdona n2
Actionscrip linakrdona n2Actionscrip linakrdona n2
Actionscrip linakrdona n2
 
2trabajo
2trabajo2trabajo
2trabajo
 
2. tutorial unity3d-disparo
2.  tutorial unity3d-disparo2.  tutorial unity3d-disparo
2. tutorial unity3d-disparo
 
2. tutorial unity3d-disparo
2.  tutorial unity3d-disparo2.  tutorial unity3d-disparo
2. tutorial unity3d-disparo
 
Agregar una imagen
Agregar una imagenAgregar una imagen
Agregar una imagen
 
Jowin Rojas Venecia IED
Jowin Rojas Venecia IEDJowin Rojas Venecia IED
Jowin Rojas Venecia IED
 

Mais de Fernando Salamero

(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
(Anotaciones) Ciencia (Cuestiones) que la tiza no propone(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
(Anotaciones) Ciencia (Cuestiones) que la tiza no proponeFernando Salamero
 
Ciencia (Cuestiones) que la tiza no propone
Ciencia (Cuestiones) que la tiza no proponeCiencia (Cuestiones) que la tiza no propone
Ciencia (Cuestiones) que la tiza no proponeFernando Salamero
 
(Con anotaciones) En busca de la Física
(Con anotaciones) En busca de la Física(Con anotaciones) En busca de la Física
(Con anotaciones) En busca de la FísicaFernando Salamero
 
Timeline - En busca de la Física
Timeline - En busca de la FísicaTimeline - En busca de la Física
Timeline - En busca de la FísicaFernando Salamero
 
Programación de Videojuegos con Python y Pilas (X)
Programación de Videojuegos con Python y Pilas (X)Programación de Videojuegos con Python y Pilas (X)
Programación de Videojuegos con Python y Pilas (X)Fernando Salamero
 
Programación de Videojuegos con Python y Pilas (VI)
Programación de Videojuegos con Python y Pilas (VI)Programación de Videojuegos con Python y Pilas (VI)
Programación de Videojuegos con Python y Pilas (VI)Fernando Salamero
 
Programación con Pygame VII
Programación con Pygame VIIProgramación con Pygame VII
Programación con Pygame VIIFernando Salamero
 

Mais de Fernando Salamero (16)

(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
(Anotaciones) Ciencia (Cuestiones) que la tiza no propone(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
 
Ciencia (Cuestiones) que la tiza no propone
Ciencia (Cuestiones) que la tiza no proponeCiencia (Cuestiones) que la tiza no propone
Ciencia (Cuestiones) que la tiza no propone
 
(Con anotaciones) En busca de la Física
(Con anotaciones) En busca de la Física(Con anotaciones) En busca de la Física
(Con anotaciones) En busca de la Física
 
Timeline - En busca de la Física
Timeline - En busca de la FísicaTimeline - En busca de la Física
Timeline - En busca de la Física
 
Jovenes físicos
Jovenes físicosJovenes físicos
Jovenes físicos
 
Programación de Videojuegos con Python y Pilas (X)
Programación de Videojuegos con Python y Pilas (X)Programación de Videojuegos con Python y Pilas (X)
Programación de Videojuegos con Python y Pilas (X)
 
Programación de Videojuegos con Python y Pilas (VI)
Programación de Videojuegos con Python y Pilas (VI)Programación de Videojuegos con Python y Pilas (VI)
Programación de Videojuegos con Python y Pilas (VI)
 
Python básico I
Python básico IPython básico I
Python básico I
 
Python (ejercicios)
Python (ejercicios)Python (ejercicios)
Python (ejercicios)
 
Python (práctica 4)
Python (práctica 4)Python (práctica 4)
Python (práctica 4)
 
Python (práctica 3)
Python (práctica 3)Python (práctica 3)
Python (práctica 3)
 
Python (práctica 2)
Python (práctica 2)Python (práctica 2)
Python (práctica 2)
 
Python (práctica 1)
Python (práctica 1)Python (práctica 1)
Python (práctica 1)
 
Iniciación a python
Iniciación a pythonIniciación a python
Iniciación a python
 
Programación con Pygame VII
Programación con Pygame VIIProgramación con Pygame VII
Programación con Pygame VII
 
Aventura
AventuraAventura
Aventura
 

Último

IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO YESSENIA 933623393 NUEV...
IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO  YESSENIA 933623393 NUEV...IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO  YESSENIA 933623393 NUEV...
IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO YESSENIA 933623393 NUEV...YobanaZevallosSantil1
 
c3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptx
c3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptxc3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptx
c3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptxMartín Ramírez
 
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptxPPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptxOscarEduardoSanchezC
 
Los Nueve Principios del Desempeño de la Sostenibilidad
Los Nueve Principios del Desempeño de la SostenibilidadLos Nueve Principios del Desempeño de la Sostenibilidad
Los Nueve Principios del Desempeño de la SostenibilidadJonathanCovena1
 
PINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).ppt
PINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).pptPINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).ppt
PINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).pptAlberto Rubio
 
cuadernillo de lectoescritura para niños de básica
cuadernillo de lectoescritura para niños de básicacuadernillo de lectoescritura para niños de básica
cuadernillo de lectoescritura para niños de básicaGianninaValeskaContr
 
Uses of simple past and time expressions
Uses of simple past and time expressionsUses of simple past and time expressions
Uses of simple past and time expressionsConsueloSantana3
 
FICHA DE MONITOREO Y ACOMPAÑAMIENTO 2024 MINEDU
FICHA DE MONITOREO Y ACOMPAÑAMIENTO  2024 MINEDUFICHA DE MONITOREO Y ACOMPAÑAMIENTO  2024 MINEDU
FICHA DE MONITOREO Y ACOMPAÑAMIENTO 2024 MINEDUgustavorojas179704
 
Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...
Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...
Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...fcastellanos3
 
CIENCIAS NATURALES 4 TO ambientes .docx
CIENCIAS NATURALES 4 TO  ambientes .docxCIENCIAS NATURALES 4 TO  ambientes .docx
CIENCIAS NATURALES 4 TO ambientes .docxAgustinaNuez21
 
PROGRAMACION ANUAL DE MATEMATICA 2024.docx
PROGRAMACION ANUAL DE MATEMATICA 2024.docxPROGRAMACION ANUAL DE MATEMATICA 2024.docx
PROGRAMACION ANUAL DE MATEMATICA 2024.docxEribertoPerezRamirez
 
Mapa Mental de estrategias de articulación de las areas curriculares.pdf
Mapa Mental de estrategias de articulación de las areas curriculares.pdfMapa Mental de estrategias de articulación de las areas curriculares.pdf
Mapa Mental de estrategias de articulación de las areas curriculares.pdfvictorbeltuce
 
5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf
5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf
5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdfOswaldoGonzalezCruz
 
Técnicas de grabado y estampación : procesos y materiales
Técnicas de grabado y estampación : procesos y materialesTécnicas de grabado y estampación : procesos y materiales
Técnicas de grabado y estampación : procesos y materialesRaquel Martín Contreras
 
periodico mural y sus partes y caracteristicas
periodico mural y sus partes y caracteristicasperiodico mural y sus partes y caracteristicas
periodico mural y sus partes y caracteristicas123yudy
 
Fundamentos y Principios de Psicopedagogía..pdf
Fundamentos y Principios de Psicopedagogía..pdfFundamentos y Principios de Psicopedagogía..pdf
Fundamentos y Principios de Psicopedagogía..pdfsamyarrocha1
 

Último (20)

IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO YESSENIA 933623393 NUEV...
IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO  YESSENIA 933623393 NUEV...IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO  YESSENIA 933623393 NUEV...
IV SES LUN 15 TUTO CUIDO MI MENTE CUIDANDO MI CUERPO YESSENIA 933623393 NUEV...
 
DIA INTERNACIONAL DAS FLORESTAS .
DIA INTERNACIONAL DAS FLORESTAS         .DIA INTERNACIONAL DAS FLORESTAS         .
DIA INTERNACIONAL DAS FLORESTAS .
 
c3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptx
c3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptxc3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptx
c3.hu3.p1.p2.El ser humano y el sentido de su existencia.pptx
 
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptxPPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
PPT GESTIÓN ESCOLAR 2024 Comités y Compromisos.pptx
 
Los Nueve Principios del Desempeño de la Sostenibilidad
Los Nueve Principios del Desempeño de la SostenibilidadLos Nueve Principios del Desempeño de la Sostenibilidad
Los Nueve Principios del Desempeño de la Sostenibilidad
 
PINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).ppt
PINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).pptPINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).ppt
PINTURA ITALIANA DEL CINQUECENTO (SIGLO XVI).ppt
 
La luz brilla en la oscuridad. Necesitamos luz
La luz brilla en la oscuridad. Necesitamos luzLa luz brilla en la oscuridad. Necesitamos luz
La luz brilla en la oscuridad. Necesitamos luz
 
cuadernillo de lectoescritura para niños de básica
cuadernillo de lectoescritura para niños de básicacuadernillo de lectoescritura para niños de básica
cuadernillo de lectoescritura para niños de básica
 
Uses of simple past and time expressions
Uses of simple past and time expressionsUses of simple past and time expressions
Uses of simple past and time expressions
 
FICHA DE MONITOREO Y ACOMPAÑAMIENTO 2024 MINEDU
FICHA DE MONITOREO Y ACOMPAÑAMIENTO  2024 MINEDUFICHA DE MONITOREO Y ACOMPAÑAMIENTO  2024 MINEDU
FICHA DE MONITOREO Y ACOMPAÑAMIENTO 2024 MINEDU
 
Earth Day Everyday 2024 54th anniversary
Earth Day Everyday 2024 54th anniversaryEarth Day Everyday 2024 54th anniversary
Earth Day Everyday 2024 54th anniversary
 
Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...
Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...
Estas son las escuelas y colegios que tendrán modalidad no presencial este lu...
 
CIENCIAS NATURALES 4 TO ambientes .docx
CIENCIAS NATURALES 4 TO  ambientes .docxCIENCIAS NATURALES 4 TO  ambientes .docx
CIENCIAS NATURALES 4 TO ambientes .docx
 
PROGRAMACION ANUAL DE MATEMATICA 2024.docx
PROGRAMACION ANUAL DE MATEMATICA 2024.docxPROGRAMACION ANUAL DE MATEMATICA 2024.docx
PROGRAMACION ANUAL DE MATEMATICA 2024.docx
 
Mapa Mental de estrategias de articulación de las areas curriculares.pdf
Mapa Mental de estrategias de articulación de las areas curriculares.pdfMapa Mental de estrategias de articulación de las areas curriculares.pdf
Mapa Mental de estrategias de articulación de las areas curriculares.pdf
 
5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf
5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf
5° SEM29 CRONOGRAMA PLANEACIÓN DOCENTE DARUKEL 23-24.pdf
 
TL/CNL – 2.ª FASE .
TL/CNL – 2.ª FASE                       .TL/CNL – 2.ª FASE                       .
TL/CNL – 2.ª FASE .
 
Técnicas de grabado y estampación : procesos y materiales
Técnicas de grabado y estampación : procesos y materialesTécnicas de grabado y estampación : procesos y materiales
Técnicas de grabado y estampación : procesos y materiales
 
periodico mural y sus partes y caracteristicas
periodico mural y sus partes y caracteristicasperiodico mural y sus partes y caracteristicas
periodico mural y sus partes y caracteristicas
 
Fundamentos y Principios de Psicopedagogía..pdf
Fundamentos y Principios de Psicopedagogía..pdfFundamentos y Principios de Psicopedagogía..pdf
Fundamentos y Principios de Psicopedagogía..pdf
 

Programación con Pygame IV

  • 1. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO Sprites Mario se convierte en nuestro Sprite Los programas que hemos realizado hasta ahora con PyGame son (relativamente) bastante elaborados y, a medida que crezca la complejidad, pueden volverse más y más enrevesados. ¡Afortunadamente, PyGame se puede encargar por nosotros de muchas más cosas! En efecto, hay determinados detalles que hemos implementado por nuestra cuenta y que PyGame ya incorpora de una manera más simple. Sólo hay que aprenderla. No temas; el trabajo que has empleado hasta aquí te habrá ayudado a crecer como programador/ programadora. En particular, y gracias al concepto de programación dirigida a objetos, PyGame crea y gestiona los sprites de manera nativa. Una vez comprendido, ¡todo se vuelve más sencillo! En las siguientes páginas, vamos a coger una imagen del famoso Mario de Nintendo y vamos a hacer que se desplace como en los juegos de plataformas (gracias a Kevin Harris por un pequeño programa de demostración en el que nos estamos apoyando). De paso aprenderemos cómo modificar el movimiento para que parezca no lineal, simulando la gravedad. ¡Vamos allá! PÁGINA 1 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 2. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario01.py En este primer paso sólo vamos a mostrar la imagen de Mario como resultado, pero internamente habremos creado un sprite que luego nos servirá para continuar y ampliarlo en los siguientes casos. Éste es el código: # -*- coding: utf-8 -*- #----------------------------------------------------------------------- # mario01.py # Implemetación de sprites #----------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) # Inicializar el sprite sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() PÁGINA 2 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 3. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() Tras la importación de las librerías habituales, lo primero que hacemos en el código anterior es definir nuestra nueva clase de sprite que deriva de la clase de sprite de PyGame. class MiSprite( pygame.sprite.Sprite ): pygame.sprite.Sprite es la clase de sprite que implementa PyGame de forma nativa. Al ponerla entre paréntesis le decimos a Pygame que cree la nuestra a partir de aquella. Recuerda que toda clase debería tener definida la función especial __init__() en la que pueden ponerse todas aquellas tareas que queremos que se realicen al crearse los sprites. ¡Ojo, algo muy importante! Cuando definamos una clase basada en otra, es muy conveniente que llamemos a su vez a la función que inicializa la clase original. Eso se consigue escribiéndolo en primer lugar: def __init__( self, dibujo ): pygame.sprite.Sprite.__init__( self ) Un secreto con respecto al significado de self. Cuando creamos un objeto del tipo de la clase que estamos definiendo, self representa al objeto mismo. Es un convenio muy útil pero que al programador primerizo le causa algún que otro dolor de cabeza. Python está construido de forma que en toda función que se defina dentro de una clase, el primer argumento debe ser siempre self. Sin embargo, cuando se invoca a estas funciones, nunca se pone el susodicho self. Python se encarga por sí mismo de pasárselo a la función y no tienes que ocuparte tú de ello. Acuérdate siempre de esto; en la definición sí, en el uso no. A su vez, si quieres definir variables que pertenezcan al objeto para poder utilizarlas posteriormente, siempre debes definirlas con el como propiedades del objeto self, es decir, debes definirlas con el self. por delante. En nuestro ejemplo, definimos la variable self.image para almacenar en ella el dibujo que tendrá nuestro sprite: self.image = pygame.image.load(dibujo) PÁGINA 3 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 4. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO De hecho, self.image es una propiedad que PyGame nos obliga a definir en nuestros sprites, pues es la que usará automáticamente para dibujarlos en pantalla. Fíjate cómo lo hemos hecho; en la definición de la función __init__() hemos puesto un segundo argumento, además de self, dibujo. Allí le pasaremos la imagen cuando creemos el objeto que representa nuestro sprite de Mario. En la definición de self.image usamos, por lo tanto, la función de PyGame que ya conocemos para cargarla, pygame.image.load(). A su vez, también como sabemos, conviene convertir la imagen al formato adecuado para Pygame, así que la siguiente línea es self.image = self.image.convert() ¿Te suena verdad? El resultado de convertir la imagen lo volvemos a almacenar en la variable self.image. ¡Ya está preparada para ser utilizada! ¿Qué mas cosas hemos puesto en la función __init__() ? Hay otra propiedad de los sprites que PyGame nos obliga a definir también y es self.rect. Se trata, ni más ni menos, de una variable de tipo rect que almacena la posición y el tamaño tiene nuestro sprite. self.rect = self.image.get_rect() self.rect.topleft = (0, 150) La manera más sencilla de obtener el rect es decirle a Python que lo calcule por sí misma llamando a la función miembro de una imagen get_rect(). Esta función nos devuelve el tamaño de la imagen a la que pertenece (en forma de rect). En la siguiente línea lo único que hacemos es indicar en qué posición va a estar el sprite modificando las propiedades top y left del rect (consulta la documentación de PyGame). Inicialmente, estará a la izquierda de la ventana (0) y a 150 pixeles del borde superior. ¡Ya tenemos definido nuestro sprite! Lo siguiente es inicializar PyGame y crear la Surface donde vamos a mostrar la animación. Optamos por una ventana de 640x480 pixeles, con las opciones que PyGame toma por defecto. pygame.init() visor = pygame.display.set_mode((640, 480)) Ha llegado el momento importante; vamos a crear a Mario. Crear un sprite es un proceso que, comúnmente, requiere dos pasos. Primero hay que crear al propio sprite. Y segundo hay que agruparlo. ¿Qué quiere decir esto? De cara a manejar múltiples sprites, nos interesa tenerlos clasificados (el protagonista, los malos, la comida...). PyGame nos dará posteriormente herramientas para trabajar con todos ellos a la vez o por separado, gestionar sus colisiones, etc. Esto hay que hacerlo siempre, incluso cuando, como ahora, tenemos un sólo sprite. Veamos: sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) Hemos creado dos variables. La primera, sprite, contiene nuestro sprite de Mario. La segunda, grupo, contiene el grupo al que pertenece nuestro sprite. ¿Cómo lo hemos hecho? Para empezar, hemos invocado el nombre de la clase del sprite pasándole como argumento el nombre del archivo que contiene la imagen que vamos a PÁGINA 4 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 5. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO usar. Fíjate en la definición de la clase; allí verás que la función __init__() la hemos puesto con dos parámetros, self (que recuerda que se ignora cuando se llama a la función) y otra más que luego usamos en la definición para indicar la imagen del sprite. Para añadir un sprite a un grupo usamos pygame.sprite.RenderUpdates(); esta función nos crea un grupo de sprites al que añade el que le pasemos como argumento. El grupo, como hemos dicho, lo almacenamos en una variable que hemos llamado (qué imaginación) grupo. Dicho sea de paso, si tuviéramos otro sprite y quisiéramos añadirlo a este grupo, bastaría que escribiéramos grupo.add(nombre_de_otro_sprite). ¡Fácil! Lo siguiente es algo que va a hacer mucho más simple lo que hasta ahora hemos hecho más complicado; controlar la velocidad de la animación. En los tutoriales anteriores lo hemos hecho a mano, mirando el tiempo que pasaba y ajustando la diferencia hasta que se conseguía el tiempo requerido. Afortunadamente, Python se puede encargar automáticamente de eso por ti. Para ello necesitamos crear un objeto especial: reloj = pygame.time.Clock() pygame.time.Clock() nos devuelve un objeto que almacenamos en la variable reloj y que se encargará de controlar los fotogramas por segundo a los que se va mostrar la animación. Lo podemos ver al comienzo del bucle habitual: while 1: #Fijar la animación a 60 fps reloj.tick(60) ¡Qué sencillo resulta ahora! Como quiero que la animación se reproduzca a 60 fotogramas por segundo y no más rápido, basta con que lo indique usando la función tick() del objeto reloj. Python, por sí mismo, se encargará de esperar lo suficiente (si hace falta) para conseguirlo... Con la seguridad de que lo tenemos todo controlado (incluido el típico código de eventos que solemos usar para salir del programa), podemos pasar a la tarea de dibujar en pantalla el fotograma. Una vez conocido el sistema, es muy sencillo. Piensa que, en cada pasada del bucle, lo que deseas hacer es mirar todos los sprites que tengas, ver donde tienes que ponerlos, borrarlos de donde estaban antes y dibujarlos en sus nuevas posiciones. Si te fijas, es precisamente eso lo que hemos hecho en el código: # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() Aquí podemos ver la utilidad del concepto de grupo de PyGame. Para decirle al grupo que actualice las posiciones (esto es, que averigüe cuáles deben ser las nuevas posiciones) de todos sus sprites basta usar su función miembro update(). Y para decirle PÁGINA 5 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 6. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO que los dibuje en esas posiciones usamos draw() pasándole como argumento la surface en la que ha de hacerse (nuestro visor). Finalmente, como siempre en PyGame, volcamos toda esa información en pantalla para que la muestre con pygame.display.update(). Te puedes preguntar ¿y cómo sabe PyGame, cuando llamo a grupo.update() dónde están las nuevas posiciones de los sprites? En realidad, grupo.update() lo que hace es llamar a las funciones update() de todos los sprites que pertencen al grupo. Como nosotros no hemos definido esa función en MiSprite, PyGame no hace nada y deja a Mario siempre en la misma posición. Ejecuta el programa: Una vez que comprendas el proceso, verás que es sencillo y potente. Prueba a eliminar los comentarios; el código que resulta es bastante breve y fácil de entender PÁGINA 6 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 7. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario02.py La ventaja de utilizar la programación dirigida a objetos que incorpora PyGame es que modificar el comportamiento de los sprites es muy sencillo. Vamos a darle movimiento a Mario. Nada más simple: # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario02.py # Movimiento sencillo #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) def update(self): # Modificar la posición del sprite self.rect.move_ip(1,0) # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) # Inicializar el sprite sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: PÁGINA 7 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 8. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() ¡Extremadamente sencillo! ¿Recuerdas que, en cada fotograma, grupo.update() llama a la función update() de cada sprite para saber dónde debe dibujarlo? Bueno, pues simplemente debemos definir esa función dentro de nuestra clase para tener la tarea hecha. Esto es lo único que hemos añadido al código: def update(self): # Modificar la posición del sprite self.rect.move_ip(1,0) De paso, usamos otra función incorporada, move_ip(), que también hace las cosas más sencillas. En lugar de modificar a mano las coordenadas de self.rect, el rectángulo que define la posición y el tamaño del sprite, move_ip() toma de argumento dos valores que indican cuánto hay que desplazar el rect. En nuestro ejemplo, este desplazamiento es de 1 pixel hacia la derecha y 0 pixeles hacia abajo (es decir, no se desplaza en dirección vertical). Terminado. Si ejecutas el programa verás a Mario desplazándose lentamente por la pantalla; exactamente a 60 pixeles por segundo (1 pixel en cada fotograma, 60 fotogramas por segundo). PÁGINA 8 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 9. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario03.py Implementar el rebote es igual de sencillo: # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario03.py # Rebote #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) # Definir las velocidad self.dx = 1 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,0) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) # Inicializar el sprite sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación PÁGINA 9 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 10. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() La forma de conseguir el rebote ya la conocemos; ver cuando se llega al borde de la ventana y cambiar el sentido del movimiento cambiando de signo la cantidad que sumas a la posición. Lógicamente, para poder cambiar ese signo, necesitamos almacenar la cantidad que sumamos a la posición en una variable. Como es un movimiento en el eje horizontal, llamemos a esa variable dx. Como es una variable que ha de pertenecer al sprite, vamos a poner su definición en la función __init__() de la clase y, por lo tanto, deberemos añadirle al nombre el ya conocido self: # Definir las velocidad self.dx = 1 Bien. Una vez hecho esto, implementar el rebote de Mario requiere modificar la definición de la función update() del sprite: def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,0) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx En efecto, primero movemos el sprite la cantidad deseada (ahora es self.dx) y luego miramos si se ha llegado a uno de los extremos de la pantalla, en cuyo caso cambiamos el movimiento cambiando el signo de self.dx. ¿Ves qué sencillo? PÁGINA 10 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 11. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario04.py Un nuevo paso. Esta vez, al igual que hacíamos con Guy, vamos a invertir la imagen del sprite cuando éste rebote. Éste es el código: # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario04.py # Rebote invirtiendo el sprite #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) # Definir la velocidad self.dx = 1 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,0) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) # Inicializar el sprite sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() PÁGINA 11 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 12. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() ¿Puedes creer que sea algo tan simple? Pues sí: en el mismo lugar del código donde miramos si el sprite ha llegado al borde (y cambiamos la dirección del movimiento en caso afirmativo), lo único que hacemos es transformar la imagen de Mario por su reflejo horizontal if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) De nuevo, igual que hicimos con Guy, la función pygame.transform.flip() nos permite hacer esa inversión de la imagen. El resultado, lo volvemos a almacenar en self.image que contiene el aspecto de nuestro sprite y, a partir de entonces, nuestro Mario estará mirando en su movimiento hacia el otro lado. ¡Perfecto! Espero que, en este punto, comprendas las ventajas de la programación dirigida a objetos y del concepto de Sprite de PyGame; todo su comportamiento lo incluimos en la definición de la clase y cuando usemos un objeto de ese tipo, automáticamente se comportará como tal. Ello hace que los programas sean mucho más fácilmente modificables y ampliables, como estamos viendo. PÁGINA 12 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 13. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO PÁGINA 13 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 14. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario05.py Implementar el movimiento en la dirección vertical, incluido el rebote correspondiente, te debería resultar ahora bastante fácil: # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario05.py # Implementando el movimiento vertical #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) # Definir las velocidades self.dx = 1 self.dy = 1 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,self.dy) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) if self.rect.top < 0 or self.rect.bottom > 480: self.dy = -self.dy # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) # Inicializar el sprite sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) PÁGINA 14 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 15. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() ¿Hace falta explicar algo? Sólo hemos añadido en __init__() la nueva velocidad vertical self.dy y en update() la hemos añadido al movimiento y a la comprobación del rebote. PÁGINA 15 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 16. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario06.py Hasta ahora sólo hemos hecho movimientos rectilíneos y uniformes. ¿Qué tal simular algo más real, como una caída con gravedad? # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario06.py # Simular la gravedad #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) # Definir las velocidades self.dx = 1 self.dy = 1 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,self.dy) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) if self.rect.top < 0 or self.rect.bottom > 480: self.dy = -self.dy # Simular la gravedad sumando una cantidad a la velocidad vertical self.dy = self.dy + 0.5 # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) # Inicializar el sprite PÁGINA 16 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 17. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() ¿Te podías imaginar que era tan sencillo? Lo único que hemos hecho ha sido añadir en la función update() la siguiente línea de código: self.dy = self.dy + 0.5 La explicación es muy simple. La gravedad lo único que hace es empujarnos hacia abajo de manera constante. Y la manera de hacerlo en la función update() es, por lo tanto, sumar una cantidad constante a la velocidad en el eje vertical. Fíjate que tiene precisamente el efecto deseado; cuando el sprite va hacia arriba (self.dy es entonces negativa) al sumarle 0.5 lo que hace es frenarse y cuando va hacia abajo (self.dy positiva) acelerarse. Por supuesto, sin más que variar ese 0.5 conseguimos una gravedad más o menos intensa. ¡Ejecuta el programa! Veras como el rebote es ahora más divertido... No obstante, hay dos detalles que debemos cuidar. El primero es que en mucho juegos tipo plataforma, no queremos que el protagonista se frene y que rebote siempre a la misma altura, no que se vaya frenando. Lo segundo es que tenemos un pequeño bug; si esperamos lo suficiente, veremos como Mario... ¡termina por atravesar los bordes de la ventana! En el próximo paso veremos cómo solucionar esto. PÁGINA 17 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 18. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario07.py El que el rebote sea siempre a la misma altura y el que Mario termine atravesando el suelo de la ventana pueden solucionarse con una sola línea: # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario07.py # Movimiento de plataforma #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (0, 150) # Definir las velocidades self.dx = 5.0 self.dy = 1.0 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,self.dy) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) self.rect.move_ip(self.dx,self.dy) if self.rect.top < 0 or self.rect.bottom > 480: self.dy = -self.dy self.rect.move_ip(self.dx,self.dy) # Simular la gravedad sumando una cantidad a la velocidad vertical self.dy = self.dy + 0.5 # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) PÁGINA 18 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 19. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO # Inicializar el sprite sprite = MiSprite("mario.bmp") grupo = pygame.sprite.RenderUpdates( sprite ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() En efecto, basta darle al sprite un pequeño empujoncito extra en el momento en el que llega al borde. Eso nos deja el movimiento con el mismo valor que justo antes de producirse el rebote, con lo que llegará hasta la misma altura al subir (observa que la altura a la que llega Mario es como un quesito y ese 0.5 que añadimos a la velocidad como un ratón; va mordiéndole y quitando un trozo tras otro hasta que lo termina, de ahí que el rebote vaya, de partida, disminuyendo poco a poco) y no se producirán efectos extraños en las paredes. if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) self.rect.move_ip(self.dx,self.dy) if self.rect.top < 0 or self.rect.bottom > 480: self.dy = -self.dy self.rect.move_ip(self.dx,self.dy) Por cierto, si necesitáramos solucionar el tema de atravesar el suelo por su cuenta, tampoco sería complicado. ¿Te imaginas cómo? Fácil; antes de cambiar la posición del sprite con move_ip() deberías comprobar si ya está en el suelo, en cuyo caso deberías poner el valor de self.dy a cero para que dejara de bajar. (Pregunta: ¿Cómo saber si los pies de Mario están en el borde de la ventana? Respuesta: con el atributo bottom que tiene todo objeto de tipo rect) PÁGINA 19 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 20. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario08.py Ya que estamos trabajando con sprites. ¿Por qué limitarnos a un sólo Mario? Traigamos a su hermano gemelo a la fiesta... # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario08.py # Varios sprites #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo, posX, posY ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (posX, posY) # Definir las velocidades self.dx = 5.0 self.dy = 1.0 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,self.dy) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) self.rect.move_ip(self.dx,self.dy) if self.rect.top < 0 or self.rect.bottom > 480: self.dy = -self.dy self.rect.move_ip(self.dx,self.dy) # Simular la gravedad sumando una cantidad a la velocidad vertical self.dy = self.dy + 0.5 # Inicializar PyGame y crear la Surface del juego pygame.init() visor = pygame.display.set_mode((640, 480)) PÁGINA 20 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 21. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO # Inicializar los sprites sprite = MiSprite("mario.bmp", 0, 150) grupo = pygame.sprite.RenderUpdates( sprite ) sprite2 = MiSprite("mario.bmp", 210, 50) grupo.add( sprite2 ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Actualizar el sprite grupo.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) # Mostrar la animación pygame.display.update() Para empezar, hemos modificado ligeramente la definición de nuestro tipo de sprite ya que si no todos los sprites que creemos de este tipo comenzarán en el mismo sitio (y por tanto sólo veríamos uno). Esto es fácil de solucionar; ponemos dos parámetros más en la función miembro __init__() que inicializa la clase. def __init__( self, dibujo, posX, posY ): Los parámetros posX y posY se encargarán de situar en su posición inicial al sprite. Ello quiere decir que hay que modificar una línea más de esta función: self.rect.topleft = (posX, posY) para que así, en efecto, el sprite se posicione allí al principio. Lo último que queda es, simplemente, crear los sprites: sprite = MiSprite("mario.bmp", 0, 150) grupo = pygame.sprite.RenderUpdates( sprite ) sprite2 = MiSprite("mario.bmp", 210, 50) grupo.add( sprite2 ) PÁGINA 21 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 22. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO Respecto del primer Mario, poco que decir. Lo único que hemos modificado es que, ahora, en la creación del sprite hay que indicar la posición en la que lo queremos. Con el segundo sprite hacemos lo mismo (con otra posición distinta) y, como ya está creado el grupo de sprites, lo añadimos con la función miembro add(). Dos cosas podrás notar cuando ejecutes el programa. La primera es que, como la imagen de Mario no tiene transparencias, cuando se superponen los dos gemelos se ve el cuadrado blanco que envuelve a la imagen. La segunda es que cada sprite ignora al otro. ¿Cómo podríamos gestionar la colisión entre ambos de manera que, por ejemplo, rebotaran? El problema de la transparencia, en este caso, es muy fácil de solucionar ya que sólo hay que decirle al sprite qué color ha de tomar como transparente (para no dibujarlo). Eso se consigue añadiendo una sola línea el la función __init__() del sprite: self.image.set_colorkey((255,255,255)) La función set_colorkey() es una función miembro de cualquier surface (y una imagen es a su vez una surface) que toma un argumento que no es si no el color que se usará como transparente. Si la añades y lanzas el programa, verás que ya no aparece ese cuadrado blanco tan molesto alrededor de Mario. Respecto de la colisión de los sprites... tendremos que pasar a la última versión del programa. PÁGINA 22 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 23. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO mario09.py Hay varias formas de abordar el tema. La que viene a continuación es sólo una de las más sencillas: # -*- coding: utf-8 -*- #------------------------------------------------------------------- # mario09.py # Sprites con colisión #------------------------------------------------------------------- import sys import pygame from pygame.locals import * # Clase MiSprite class MiSprite( pygame.sprite.Sprite ): # Inicializador de la clase def __init__( self, dibujo, posX, posY ): # Importante: Primero hay que inicializar la clase Sprite original pygame.sprite.Sprite.__init__( self ) # Almacenar en el sprite la imagen deseada self.image = pygame.image.load(dibujo) self.image = self.image.convert() self.image.set_colorkey((255,255,255)) # Definir el rect del sprite self.rect = self.image.get_rect() self.rect.topleft = (posX, posY) # Definir las velocidades self.dx = 5.0 self.dy = 1.0 def update(self): # Modificar la posición del sprite self.rect.move_ip(self.dx,self.dy) # Comprobar si hay que cambiar el movimiento if self.rect.left < 0 or self.rect.right > 640: self.dx = -self.dx self.image = pygame.transform.flip( self.image, True, False ) self.rect.move_ip(self.dx,self.dy) if self.rect.top < 0 or self.rect.bottom > 480: self.dy = -self.dy self.rect.move_ip(self.dx,self.dy) # Simular la gravedad sumando una cantidad a la velocidad vertical self.dy = self.dy + 0.5 # Inicializar PyGame y crear la Surface del juego pygame.init() PÁGINA 23 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 24. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO visor = pygame.display.set_mode((640, 480)) # Inicializar los sprites sprite = MiSprite("mario.bmp", 0, 150) grupo = pygame.sprite.RenderUpdates( sprite ) sprite2 = MiSprite("mario.bmp", 210, 50) grupo2 = pygame.sprite.RenderUpdates( sprite2 ) # Crear un reloj para controlar la animación reloj = pygame.time.Clock() # El bucle de la animación while 1: #Fijar la animación a 60 fps reloj.tick(60) # Gestionar los eventos for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() # Mira si hay alguna colisión: if pygame.sprite.spritecollideany(sprite, grupo2): sprite.dx = -sprite.dx sprite.dy = -sprite.dy sprite2.dx = -sprite2.dx sprite2.dy = -sprite2.dy # Actualizar el sprite grupo.update() grupo2.update() # Dibujar la escena visor.fill((255,255,255)) grupo.draw( visor ) grupo2.draw( visor ) # Mostrar la animación pygame.display.update() Lo primero es una advertencia: como cualquier programador sabe, los documentos de referencia (en los que se incluyen las librerías, objetos e instrucciones disponibles en el lenguaje) son un compañero inseparable en la aventura de programar. ¿No tienes cerca la referencia de Pygame? Cógela ahora mismo. Piensa que te nombramos unas pocas funciones u objetos pero hay muchas más. Y muchas más opciones. Lo segundo es hacerte notar que hemos añadido la línea a la que nos referíamos al final del capítulo anterior, el código que consigue que el color blanco (255,255,255) se tome como transparente y no se dibuje. PÁGINA 24 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 25. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO Bien, vamos al tema de la detección de colisiones. PyGame incorpora muchas funciones que gestionan los posibles choques entre sprites y/o grupos. ¡Mira el documento de Referencia de PyGame! Como notarás enseguida, una de las maneras más cómodas es usar la función pygame.sprite.spritecollideany(). Fíjate qué pone en la referencia: spritecollideany Consulta simple para ver si un sprite colisiona con algún otro en el grupo. pygame.sprite.spritecollideany(sprite, group): return bool Consulta si el sprite dado colisiona con algún sprite en el grupo. La intersección se determina comparando el atributo Sprite.rect de cada sprite. Esta prueba de colisión puede ser mas rápida que pygame.sprite.spritecollideany() dado que tiene menos trabajo para hacer. Retornará al encontrar la primer colisión. Lo que nos interesa son dos cosas; la función toma dos argumentos (un Sprite y un Grupo) y devuelve un Booleano (True o False). En definitiva, lo que hace es mirar si el sprite que le pasamos a la función colisiona con algún sprite que pertenezca al grupo que también le pasamos, devolviéndonos True o False en consecuencia. Esto nos viene muy bien pues solo tenemos dos sprites. En programas más complejos, con muchos sprites, necesitaríamos otras funciones distintas que nos dijeran a su vez cuáles son los sprites que han colisionado, etc. He aquí otro punto importante; como suele mirarse la colisión de sprites y grupos, conviene tener separados los sprites que queremos mirar si colisionan en diferentes grupos. Típicamente, por ejemplo, tendríamos un grupo para las naves de los enemigos y otro grupo para los rayos láser. O, en el juego del Pong, un grupo para las raquetas y otro para la pelota. Ésa es la razón por la que hemos puesto lo siguiente: sprite = MiSprite("mario.bmp", 0, 150) grupo = pygame.sprite.RenderUpdates( sprite ) sprite2 = MiSprite("mario.bmp", 210, 50) grupo2 = pygame.sprite.RenderUpdates( sprite2 ) En el capítulo anterior añadíamos el sprite sprite2 al grupo grupo en el que estaba el sprite sprite. Como ahora queremos mirar cuándo chocan, definimos un nuevo grupo, grupo2. ¡Ya los tenemos separados! Lo siguiente es implementar la colisión. Como ya hemos visto más arriba la sintaxis de la función pygame.sprite.spritecollideany(), no debería ser difícil de entender: PÁGINA 25 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES
  • 26. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO # Mira si hay alguna colisión: if pygame.sprite.spritecollideany(sprite, grupo2): sprite.dx = -sprite.dx sprite.dy = -sprite.dy sprite2.dx = -sprite2.dx sprite2.dy = -sprite2.dy En el código anterior miramos si el sprite sprite ha chocado con algún miembro del grupo grupo2 (vamos, con su hermano gemelo que es el único sprite de ese grupo). En caso afirmativo, pygame.sprite.spritecollideany() devuelve True y, por tanto, se ejecuta el interior del bloque if. ¿Qué hacemos allí? Análogamente al rebote en los bordes de la ventana, cambiamos las direcciones de movimiento de los dos sprites. ¡Rebote conseguido! Sólo queda añadir la parte de código que tiene en cuenta que ahora no hay sólo un grupo para actualizar y dibujar en pantalla. Así que, en los sitios correspondientes, hay que colocar primero grupo2.update() y después grupo2.draw( visor ) Ejecuta ahora el programa... ¡Genial! Por cierto; cuando rebotan los dos marios, el uno contra el otro, no invierten su dibujo. Y si dejas que pase el tiempo suficiente, pueden llegar a engancharse... ¿Sabrías solucionarlo? Ya puestos, ¿sabrías hacer que comiencen desde una posición aleatoria? ¿Y que salgan, no dos, si no muchos marios, por ejemplo cada vez que se haga click con el ratón? Ante nosotros se extiende un campo de creatividad ilimitado... PÁGINA 26 DE 26 DURACIÓN: PERÍODOS DE DOS CLASES