SlideShare ist ein Scribd-Unternehmen logo
1 von 26
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

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
 
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
 
Introducción a las librerías PyGame y PyOpenGL
Introducción a las librerías PyGame y PyOpenGLIntroducción a las librerías PyGame y PyOpenGL
Introducción a las librerías PyGame y PyOpenGLkdeespana
 
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
 
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
 
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
 
Xna game studio presentación 02
Xna game studio   presentación 02Xna game studio   presentación 02
Xna game studio presentación 02Juan Cardona
 
Xna game studio presentación 01
Xna game studio   presentación 01Xna game studio   presentación 01
Xna game studio presentación 01Juan Cardona
 
Ejemplo 18 animación usando gamecanvas
Ejemplo 18 animación usando gamecanvasEjemplo 18 animación usando gamecanvas
Ejemplo 18 animación usando gamecanvasMercedes Reyes Carrion
 
Taller de introduccion a python con turtle
Taller de  introduccion a python  con  turtleTaller de  introduccion a python  con  turtle
Taller de introduccion a python con turtleAlbert Page
 
17528334 manual-vray-espanol-completo
17528334 manual-vray-espanol-completo17528334 manual-vray-espanol-completo
17528334 manual-vray-espanol-completoOscar Monterrosa
 

Was ist angesagt? (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)
 
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)
 
Intro pygamev2
Intro pygamev2Intro pygamev2
Intro pygamev2
 
Introducción a las librerías PyGame y PyOpenGL
Introducción a las librerías PyGame y PyOpenGLIntroducción a las librerías PyGame y PyOpenGL
Introducción a las librerías PyGame y PyOpenGL
 
Intro PyGame Capitulo 5
Intro PyGame Capitulo 5Intro PyGame Capitulo 5
Intro PyGame Capitulo 5
 
Intro Pygame Capitulo 2
Intro Pygame Capitulo 2Intro Pygame Capitulo 2
Intro Pygame Capitulo 2
 
Intro PygameCapitulo 3
Intro PygameCapitulo 3Intro PygameCapitulo 3
Intro PygameCapitulo 3
 
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)
 
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)
 
Aventura
AventuraAventura
Aventura
 
Intro PyGame Capitulo 1
Intro PyGame Capitulo 1Intro PyGame Capitulo 1
Intro PyGame Capitulo 1
 
Capitulo 4
Capitulo 4Capitulo 4
Capitulo 4
 
Intro PyGame Capitulo 0
Intro PyGame Capitulo 0Intro PyGame Capitulo 0
Intro PyGame Capitulo 0
 
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
 
Xna game studio presentación 02
Xna game studio   presentación 02Xna game studio   presentación 02
Xna game studio presentación 02
 
Xna game studio presentación 01
Xna game studio   presentación 01Xna game studio   presentación 01
Xna game studio presentación 01
 
Ejemplo 18 animación usando gamecanvas
Ejemplo 18 animación usando gamecanvasEjemplo 18 animación usando gamecanvas
Ejemplo 18 animación usando gamecanvas
 
Taller de introduccion a python con turtle
Taller de  introduccion a python  con  turtleTaller de  introduccion a python  con  turtle
Taller de introduccion a python con turtle
 
Tutorial de flash
Tutorial de flashTutorial de flash
Tutorial de flash
 
17528334 manual-vray-espanol-completo
17528334 manual-vray-espanol-completo17528334 manual-vray-espanol-completo
17528334 manual-vray-espanol-completo
 

Andere mochten auch

(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
 

Andere mochten auch (8)

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
 
(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)
 
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)
 

Ähnlich wie Programación con Pygame IV

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
 
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
 
Action script 3
Action script 3Action script 3
Action script 3YahirAyala
 
Action script 3 yahir ayala
Action script 3  yahir ayalaAction script 3  yahir ayala
Action script 3 yahir ayalaYahir17
 
ActionScript 3.0 GERMAN MIELES11-2
ActionScript 3.0 GERMAN MIELES11-2ActionScript 3.0 GERMAN MIELES11-2
ActionScript 3.0 GERMAN MIELES11-2caresucio
 
EXPOSICION PYGAME
EXPOSICION PYGAMEEXPOSICION PYGAME
EXPOSICION PYGAMEdj.l
 
Agregar una imagen
Agregar una imagenAgregar una imagen
Agregar una imagenEsmedc20
 

Ähnlich wie Programación con Pygame IV (20)

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
 
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
 
Angie tovar (1)
Angie tovar (1)Angie tovar (1)
Angie tovar (1)
 
Action script 3
Action script 3Action script 3
Action script 3
 
Action script 3 yahir ayala
Action script 3  yahir ayalaAction script 3  yahir ayala
Action script 3 yahir ayala
 
99
9999
99
 
ActionScript 3.0 GERMAN MIELES11-2
ActionScript 3.0 GERMAN MIELES11-2ActionScript 3.0 GERMAN MIELES11-2
ActionScript 3.0 GERMAN MIELES11-2
 
EXPOSICION PYGAME
EXPOSICION PYGAMEEXPOSICION PYGAME
EXPOSICION PYGAME
 
Agregar una imagen
Agregar una imagenAgregar una imagen
Agregar una imagen
 

Mehr von Fernando Salamero

Mehr von Fernando Salamero (13)

(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
 
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
 

Kürzlich hochgeladen

semana 4 9NO Estudios sociales.pptxnnnn
semana 4  9NO Estudios sociales.pptxnnnnsemana 4  9NO Estudios sociales.pptxnnnn
semana 4 9NO Estudios sociales.pptxnnnnlitzyleovaldivieso
 
TALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docx
TALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docxTALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docx
TALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docxNadiaMartnez11
 
Tema 19. Inmunología y el sistema inmunitario 2024
Tema 19. Inmunología y el sistema inmunitario 2024Tema 19. Inmunología y el sistema inmunitario 2024
Tema 19. Inmunología y el sistema inmunitario 2024IES Vicent Andres Estelles
 
Revista Apuntes de Historia. Mayo 2024.pdf
Revista Apuntes de Historia. Mayo 2024.pdfRevista Apuntes de Historia. Mayo 2024.pdf
Revista Apuntes de Historia. Mayo 2024.pdfapunteshistoriamarmo
 
Prueba libre de Geografía para obtención título Bachillerato - 2024
Prueba libre de Geografía para obtención título Bachillerato - 2024Prueba libre de Geografía para obtención título Bachillerato - 2024
Prueba libre de Geografía para obtención título Bachillerato - 2024Juan Martín Martín
 
La Sostenibilidad Corporativa. Administración Ambiental
La Sostenibilidad Corporativa. Administración AmbientalLa Sostenibilidad Corporativa. Administración Ambiental
La Sostenibilidad Corporativa. Administración AmbientalJonathanCovena1
 
2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx
2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx
2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptxRigoTito
 
OCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VS
OCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VSOCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VS
OCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VSYadi Campos
 
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdfNUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdfUPTAIDELTACHIRA
 
Prueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESO
Prueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESOPrueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESO
Prueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESOluismii249
 
Proyecto de aprendizaje dia de la madre MINT.pdf
Proyecto de aprendizaje dia de la madre MINT.pdfProyecto de aprendizaje dia de la madre MINT.pdf
Proyecto de aprendizaje dia de la madre MINT.pdfpatriciaines1993
 
FUERZA Y MOVIMIENTO ciencias cuarto basico.ppt
FUERZA Y MOVIMIENTO ciencias cuarto basico.pptFUERZA Y MOVIMIENTO ciencias cuarto basico.ppt
FUERZA Y MOVIMIENTO ciencias cuarto basico.pptNancyMoreiraMora1
 
RESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptx
RESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptxRESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptx
RESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptxpvtablets2023
 
ACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLA
ACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLAACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLA
ACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLAJAVIER SOLIS NOYOLA
 
TIENDAS MASS MINIMARKET ESTUDIO DE MERCADO
TIENDAS MASS MINIMARKET ESTUDIO DE MERCADOTIENDAS MASS MINIMARKET ESTUDIO DE MERCADO
TIENDAS MASS MINIMARKET ESTUDIO DE MERCADOPsicoterapia Holística
 
FORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURA
FORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURAFORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURA
FORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURAEl Fortí
 
Los avatares para el juego dramático en entornos virtuales
Los avatares para el juego dramático en entornos virtualesLos avatares para el juego dramático en entornos virtuales
Los avatares para el juego dramático en entornos virtualesMarisolMartinez707897
 
Concepto y definición de tipos de Datos Abstractos en c++.pptx
Concepto y definición de tipos de Datos Abstractos en c++.pptxConcepto y definición de tipos de Datos Abstractos en c++.pptx
Concepto y definición de tipos de Datos Abstractos en c++.pptxFernando Solis
 
LA LITERATURA DEL BARROCO 2023-2024pptx.pptx
LA LITERATURA DEL BARROCO 2023-2024pptx.pptxLA LITERATURA DEL BARROCO 2023-2024pptx.pptx
LA LITERATURA DEL BARROCO 2023-2024pptx.pptxlclcarmen
 

Kürzlich hochgeladen (20)

semana 4 9NO Estudios sociales.pptxnnnn
semana 4  9NO Estudios sociales.pptxnnnnsemana 4  9NO Estudios sociales.pptxnnnn
semana 4 9NO Estudios sociales.pptxnnnn
 
TALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docx
TALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docxTALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docx
TALLER DE DEMOCRACIA Y GOBIERNO ESCOLAR-COMPETENCIAS N°3.docx
 
Tema 19. Inmunología y el sistema inmunitario 2024
Tema 19. Inmunología y el sistema inmunitario 2024Tema 19. Inmunología y el sistema inmunitario 2024
Tema 19. Inmunología y el sistema inmunitario 2024
 
Revista Apuntes de Historia. Mayo 2024.pdf
Revista Apuntes de Historia. Mayo 2024.pdfRevista Apuntes de Historia. Mayo 2024.pdf
Revista Apuntes de Historia. Mayo 2024.pdf
 
Prueba libre de Geografía para obtención título Bachillerato - 2024
Prueba libre de Geografía para obtención título Bachillerato - 2024Prueba libre de Geografía para obtención título Bachillerato - 2024
Prueba libre de Geografía para obtención título Bachillerato - 2024
 
La Sostenibilidad Corporativa. Administración Ambiental
La Sostenibilidad Corporativa. Administración AmbientalLa Sostenibilidad Corporativa. Administración Ambiental
La Sostenibilidad Corporativa. Administración Ambiental
 
2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx
2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx
2 REGLAMENTO RM 0912-2024 DE MODALIDADES DE GRADUACIÓN_.pptx
 
OCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VS
OCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VSOCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VS
OCTAVO SEGUNDO PERIODO. EMPRENDIEMIENTO VS
 
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdfNUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
 
Prueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESO
Prueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESOPrueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESO
Prueba de evaluación Geografía e Historia Comunidad de Madrid 2º de la ESO
 
Proyecto de aprendizaje dia de la madre MINT.pdf
Proyecto de aprendizaje dia de la madre MINT.pdfProyecto de aprendizaje dia de la madre MINT.pdf
Proyecto de aprendizaje dia de la madre MINT.pdf
 
FUERZA Y MOVIMIENTO ciencias cuarto basico.ppt
FUERZA Y MOVIMIENTO ciencias cuarto basico.pptFUERZA Y MOVIMIENTO ciencias cuarto basico.ppt
FUERZA Y MOVIMIENTO ciencias cuarto basico.ppt
 
RESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptx
RESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptxRESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptx
RESULTADOS DE LA EVALUACIÓN DIAGNÓSTICA 2024 - ACTUALIZADA.pptx
 
ACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLA
ACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLAACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLA
ACERTIJO DE POSICIÓN DE CORREDORES EN LA OLIMPIADA. Por JAVIER SOLIS NOYOLA
 
TIENDAS MASS MINIMARKET ESTUDIO DE MERCADO
TIENDAS MASS MINIMARKET ESTUDIO DE MERCADOTIENDAS MASS MINIMARKET ESTUDIO DE MERCADO
TIENDAS MASS MINIMARKET ESTUDIO DE MERCADO
 
FORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURA
FORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURAFORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURA
FORTI-MAYO 2024.pdf.CIENCIA,EDUCACION,CULTURA
 
Los avatares para el juego dramático en entornos virtuales
Los avatares para el juego dramático en entornos virtualesLos avatares para el juego dramático en entornos virtuales
Los avatares para el juego dramático en entornos virtuales
 
Concepto y definición de tipos de Datos Abstractos en c++.pptx
Concepto y definición de tipos de Datos Abstractos en c++.pptxConcepto y definición de tipos de Datos Abstractos en c++.pptx
Concepto y definición de tipos de Datos Abstractos en c++.pptx
 
LA LITERATURA DEL BARROCO 2023-2024pptx.pptx
LA LITERATURA DEL BARROCO 2023-2024pptx.pptxLA LITERATURA DEL BARROCO 2023-2024pptx.pptx
LA LITERATURA DEL BARROCO 2023-2024pptx.pptx
 
Interpretación de cortes geológicos 2024
Interpretación de cortes geológicos 2024Interpretación de cortes geológicos 2024
Interpretación de cortes geológicos 2024
 

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