SlideShare une entreprise Scribd logo
1  sur  13
Télécharger pour lire hors ligne
PROGRAMA: STARWARS
                          
                         CURSO: 1º BACHILLERATO




StarWars: Un arcade tipo Invaders




                       (Basado en un script original de Kevin Harris)


Importación de Librerías
Se cargan las librerías habituales, incluyendo random para introducir aleatoriedad en el
juego y os para usar direccionamiento de archivos independiente de la plataforma.


Definición de Constantes
Como quiera que los tamaños de la ventana de juego se usan en varios lugares, es
conveniente almacenarlos en variables. En realidad, al no modificarse, más que variables
se habla de constantes; para distinguirlas visualmente cuando recorremos un código
largo, un método habitual es usar un nombre en mayúsculas. Hemos definido dos:
 • ANCHO: Anchura de la ventana de juego
 • ALTO: Altura de la ventana de juego



Función cargarImagen()
La tarea repetitiva de cargar una imagen desde un archivo y convertirla al formato con el
que trabaja PyGame la hemos empaquetado en esta función. La definición posee dos
 PÁGINA 1 DE 13
                              
                     CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                           
                       CURSO: 1º BACHILLERATO

argumentos, uno obligatorio (el nombre del archivo donde está la imagen) y otro
opcional que por defecto se establece como False. Si no utilizamos este segundo
argumento cuando llamemos a la función, la imagen generada no tendrá transparencia. Si
cuando la llamemos le pasamos True, se usará (fíjate en el código) como color
transparente, a la hora de dibujar, el del pixel de la imagen de coordenadas (0,0).
Hay varias cosas que comentar:
1.   os.path.join() es una función del módulo os que permite usar direcciones de
     archivos en el disco duro sin pararse a pensar en qué sistema operativo se está. Fíjate
     que este programa tiene las imágenes y los sonidos en una subcarpeta llamada data.
     Así que el sonido de explosión explode1.wav se escribiría en MacOS X y en Linux

     data/explode1.wav

     mientras que en Windows sería

     dataexplode1.wav

     Para no tener que poner ambas y encima tener que comprobar en qué sistema
     operativo se está ejecutando el juego, os.path.join() es genial, pues nos une el
     nombre de la carpeta y el archivo correspondientes de la forma adecuada
     automáticamente.
2.   try y except son lo que se denomina gestores de excepciones. Si sabes que todo va a
     funcionar correctamente no es necesario nada más, pero un buen programador prevé
     los posibles errores que puedan surgir en la ejecución del programa y los trata
     adecuadamente. Imagínate que no están las imágenes donde deben estar. El programa
     terminará con un error que a lo mejor nos es desconocido. Es allí donde entran try y
     except pues nos permiten detectar el error y hacer algo con ello. Después del try has
     de poner el código que deseas probar. Si se ejecuta sin problemas, el programa
     sigue con normalidad; pero si se produce un error, se salta a la instrucción que
     sigue al except. Allí se gestiona el tipo de error y se puede poner un mensaje, etc.
     Consulta la documentación de Python para más detalles. Una observación: en nuestro
     programa se usa la instrucción raise que lanza a su vez un error para indicar a Python
     que salga del programa (lógicamente, pues no se ha podido cargar la imagen que se
     quería).
     En cualquier caso, esto no es estrictamente necesario que aparezca en tus programas.
     Pero sí conveniente cuando se vuelven largos y complejos.
3.   En el caso de que se haya pasado el segundo argumento de la función como True, se
     procede a asignar la transparencia a la imagen. Para ello se usa la función miembro
     get_at() que toma un punto como argumento y devuelve su color. Y para usar este
     color como el color transparente usamos, como vimos en un tutorial anterior, la
     función miembro set_colorkey().
4.   Finalmente, como queremos que la función devuelva la imagen convertida, hacemos lo
     propio con un return.


Función cargarSonido()
Esta función se encarga, en forma análoga a la función anterior, de convertir un archivo de
sonido en un objeto Sound. De la misma forma que antes, si no comprobamos ningún

 PÁGINA 2 DE 13
                               
                      CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                           
                       CURSO: 1º BACHILLERATO

error, la función quedaría muy sencilla; no obstante, vamos a hacer alguna comprobación
para aprender alguna técnica nueva:
1.   Si hay algún problema con el sistema de sonido del ordenador, el programa no podrá
     ejecutarse. Antes de que nos dé algún error es mejor detectar este problema y hacer
     que no se reproduzca ningún sonido y que el resto del juego funcione sin problemas.
     La forma de hacerlo en el código es curiosa. Se define una nueva clase sinSonido que
     posee una función play(), como los sonidos. En la definición de esta función se usa
     simplemente la instrucción pass, es decir, no hacer nada. El objetivo es sencillo;
     cuando haya problemas con el sonido, se devuelve un objeto de este tipo y así cuando
     el juego invoque play() no se hará nada.
2.   Para comprobar si hay problemas con el sistema de sonido, dentro de un if (como es
     lógico) miramos si está disponible el módulo pygame.mixer (encargado de gestionar
     el sonido del juego) y también miramos si se ha inicializado correctamente con
     pygame.mixer.get_init(). En el caso de que alguno sea False, se devuelve la clase
     sinSonido del paso anterior.
3.   El resto es igual que previamente, pero ahora usando pygame.mixer.Sound() para
     cargar el archivo de sonido correspondiente.


Clase XWing
Si eres fan de Star Wars, sabrás que las naves que llevaban los rebeldes se denominaban
XWing. La clase XWing va a ser, por lo tanto, la que se encargue del sprite de la nave
de nuestro protagonista. Como tal, es una clase derivada de pygame.sprite.Sprite.
Vamos a analizar su definición por partes:
1.   En __init__() se empieza por inicializar la clase de la que procede (algo, como ya
     vimos en el último tutorial, necesario). A continuación se definen sus atributos
     obligatorios, su image y su rect, este último usando el atajo de obtenerlo de la propia
     imagen gracias a la función get_rect(). La posición en la que se comenzará el sprite
     viene indicada por center, con lo que se usan las dimensiones de la ventana para
     situarlo. Finalmente, se definen las variables dx y dy para llevar el control de la
     velocidad de la nave.
2.   Pasemos a update(), quien controla cómo vamos a cambiar la posición de la nave en
     cada fotograma. La primera instrucción es la ya conocida con move_ip() que nos
     desplaza al sprite la cantidad indicada por dx y dy. Las siguientes líneas se encargan
     simplemente, de que la nave no sobrepase los límites de la zona por la que la dejamos
     mover; horizontalmente hasta los bordes de la ventana y verticalmente hasta la mitad.
     En tales casos, se fuerza a que la coordenada correspondiente tenga el valor límite y no
     lo supere.


Clase TIEFighter
Las naves del enemigo son diferentes, son TIEFighter. Por lo demás, el proceso de
definición de esta clase es muy parecido a la anterior con algunos matices:
1.   La función __init__() usa ahora otro argumento más, posx, para permitir que las
     naves enemigas se creen de partida en lugares distintos. Eso lo podemos ver en la línea

     self.rect.centerx = posx


 PÁGINA 3 DE 13
                               
                      CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                            
                         CURSO: 1º BACHILLERATO

     que nos posiciona la nave de acuerdo a su valor (fíjate de paso que, en el eje vertical, la
     nave comienza en la coordenada 120, más arriba que la nave del protagonista). Por
     otra parte, la velocidad del sprite se genera al azar ente -5 y 5 con la instrucción

     self.dx = random.randint( -5, 5 )

     y análogamente para dy. Ésa es la manera de conseguir que cada nave enemiga se
     mueva de forma distinta.
2.   update() es muy parecido también pero ahora, al llegar al borde, se invierte el
     movimiento de la nave (ya conocemos la técnica que consiste en cambiar de signo su
     velocidad). Lo que es nuevo es la parte del código que se encarga de generar al azar
     disparos. La forma de hacerlo es muy típica. Primero hay que evitar que se dispare
     sin parar, en plan ametralladora; para eso, generamos un número aleatorio entre 1 y
     60 y solamente cuando sea 1 se procede a disparar (de lo que se encarga un if). Para
     crear el disparo, se utilizan dos objetos que se definen más tarde en el código:

     tiefighterLaserGrupo.add( TIEFighterLaser( self.rect.midbottom ) )

     Fíjate bien; en una sola instrucción estamos haciendo, en realidad, dos cosas. En
     primer lugar se crea un sprite de tipo TIEFighterLaser (es decir, el disparo) y, como
     veremos en su correspondiente __init__(), se posiciona de partida en la mitad
     inferior de la nave espacial (de donde visualmente debe de salir el disparo). En
     segundo lugar, el disparo así creado se añade al grupo tiefighterLaserGrupo con su
     función miembro add(). Para finalizar, en la última línea

     tiefighterDisparo.play()

     se ejecuta el sonido de disparo (veremos luego que tiefighterDisparo es tal sonido).


Clase XWingLaser
Esta clase define los sprites que representan los disparos de la nave del jugador. Al ser un
sprite sencillo su código también lo es. Fíjate que en su __init__() se emplea un
argumento añadido para indicar, cuando se cree el objeto correspondiente, en qué posición
hay que hacerlo (igual que vimos con las naves del enemigo). Por otra parte, en update(),
que es donde implementamos el movimiento, se hace una comprobación con un bloque if.
La primero es preguntarse si el disparo ha llegado al borde superior de la ventana
(utilizando su rect.bottom; entonces valdría 0), en cuyo caso hay que eliminar el sprite
del juego (para que no ocupe memoria y tiempo):
self.kill()
En efecto, como puedes imaginar la función miembro kill() que posee todo sprite lo
elimina por completo. Si no se da esta circunstancia, simplemente hay que mover el
disparo hacia arriba usando su rect.move_ip(). Para desplazarlo 4 pixeles,en cada
fotograma, hacia arriba, debemos pasar 0 para el incremento en el eje horizontal y -4 para
el vertical.




 PÁGINA 4 DE 13
                                
                       CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                          
                       CURSO: 1º BACHILLERATO


Clase TIEFighterLaser
Clase idéntica a la anterior con los matices de que representa a los disparos de los
enemigos en lugar de los del jugador; ahora el movimiento es hacia abajo, con lo que el
incremento en el movimiento vertical ha de ser de 4 y se comprueba si el disparo sale de la
ventana por su borde inferior y no por el superior. De paso observa el detalle de que se
emplea para posicionar el sprite su rect.midtop por que luego se ajustará su valor en
función del rect.midbottom de la nave enemiga (justo al contrario que con el disparo y la
nave del protagonista). ¿Ves por qué? Sólo tienes que pensar de dónde sale el disparo...


Cuerpo Principal del Juego
Muchas cosas ocurren en esta parte del código, aunque todas siguiendo el esquema
habitual:
1.   Inicialización

     A parte del habitual pygame.init() y de crear la Surface del juego (a la que hemos
     llamado visor) y ponerle título a la ventana, se ha usado random.seed() para
     garantizar que el juego no se repite cuando se arranca cada vez. En realidad, cuando se
     carga el módulo random el sistema ya lo realiza automáticamente. He dejado esta
     instrucción por que si le pasamos un valor numérico concreto, el sistema lo usa como
     semilla para generar números aleatorios (algo muy interesante si queremos que los
     diferentes niveles de un juego comiencen siempre de la misma forma, es tu elección).
     También se carga la imagen de fondo del juego y se sitúa en visor con la función blit()
     en las coordenadas (0,0), es decir, ocupando toda la ventana (pues tanto imagen
     como ventana tienen el mismo tamaño).


2.   Cargar Sonidos

     Se cargan y se almacenan en variables los sonidos correspondientes a los disparos del
     jugador (xwingDisparo), de los enemigos (tiefighterDisparo) y a la explosión de
     las naves a las que les hemos dado (explotar).


3.   Crear los Sprites y los Grupos

     Tenemos que crear los diferentes tipos de sprites y agruparlos adecuadamente. Para
     empezar, creamos un sprite de tipo XWing que almacenamos como objeto con el
     nombre de xwing (gran despliegue de imaginación). En la siguiente línea se crea el
     grupo de sprites al que va a pertenecer, xwingGrupo (de hecho, será su único
     miembro). A continuación con

     xwingLaserGrupo = pygame.sprite.RenderUpdates()

     creamos un grupo (de momento vacío) que almacenará los diferentes disparos láser de
     la nave del jugador. Hacemos lo propio con el grupo de sprites de las naves enemigas,
     esta vez llamado tiefighterGrupo pero, al contrario que con los disparos, creamos y
     le añadimos al grupo tres naves enemigas. ¿Ves que cada una la creamos y la
     añadimos en una sola instrucción? Por ejemplo:

 PÁGINA 5 DE 13
                              
                      CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                          
                       CURSO: 1º BACHILLERATO

     tiefighterGrupo.add( TIEFighter( 150 ) )

     Crea un sprite de tipo TIEFighter en la posición de coordenada horizontal 150 e
     inmediatamente lo añade al grupo tiefighterGrupo. Finalmente, creamos también el
     grupo vacío tiefighterLaserGrupo de los disparos enemigos.
4.   Definición de variables de útiles

     Antes de empezar con el bucle de animación del juego, definimos tres variables
     que nos serán de utilidad. La variable jugando nos indica que el juego está en activo.
     La usaremos en el bucle while del juego y bastará poner su valor a False, por lo tanto,
     para que se salga del bucle y termine el juego. intervaloEnemigos lo vamos a usar
     para indicar cada cuanto hay que crear un nuevo enemigo. Inicialmente está a 0 y se
     irá incrementando en cada fotograma. Cuando llegue a un determinado valor (200,
     como veremos luego), será el momento de crear un enemigo más, poner la variable a 0
     y vuelta a empezar. Por último, reloj es un objeto tipo Clock que, como ya vimos en
     un tutorial anterior, nos permitirá ajustar automáticamente la velocidad de
     reproducción de la animación del juego.

5.   Bucle del Juego

     Pasamos al bucle principal del juego en el que cada iteración representa un
     fotograma de la animación. De hecho, la primera línea y el uso de reloj nos indica
     que la velocidad de reproducción va a ser de 60 fotogramas por segundo. Lo
     siguiente es comprobar los eventos que hayan ocurrido y nos interesen. Aquí hemos
     de decidir si hay que terminar el juego, o bien por que el jugador haya hecho click
     para cerrar la ventana (evento de tipo QUIT) o bien que haya pulsado la tecla
     escape (evento de tipo KEYDOWN, tecla pulsada K_ESCAPE). Todo esto nos
     debería resultar familiar.
     Ahora viene una decisión importante. Cuando miramos las teclas que ha pulsado
     el jugador para gestionar el juego, lo podemos hacer de dos formas. Una es mirando
     en la cola de eventos (como acabamos de hacer) y otra es llamando a la función

     pygame.key.get_pressed()

     y almacenando el resultado en una variable. El resultado de lo anterior es un
     diccionario en el que para cada tecla nos devuelve el valor True o False según
     esté pulsada o no. ¿Qué método usar? Cada uno tiene sus ventajas y sus
     inconvenientes. El matiz está en que con la función pygame.key.get_pressed()
     averiguamos si una tecla está pulsada mientras que con la cola de eventos lo
     averiguamos en el momento en el que se ha pulsado. La diferencia es
     fundamental. En el movimiento de la nave, nos basta con saber si está pulsada la tecla
     correspondiente y mover la nave mientras dure la pulsación, pero en los disparos nos
     interesa el momento mismo en el que se produce dicha pulsación, pues le corresponde
     un único disparo y entonces necesitamos el método de la cola de eventos (en caso
     contrario, mientras estuviera la tecla pulsada tendríamos una ráfaga de disparos y el
     juego sería muy fácil).
     Dicho esto, podemos entender que se mire, en el evento KEYDOWN si se ha pulsado
     la tecla espacio (K_SPACE). En caso afirmativo se crea el disparo. ¿Cómo? Con

     xwingLaserGrupo.add( XWingLaser( xwing.rect.midtop ) )

 PÁGINA 6 DE 13
                              
                      CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                                
                           CURSO: 1º BACHILLERATO

  creamos en una sola instrucción un sprite tipo XWingLaser que se sitúa justo encima
  de la nave del jugador y centrada (xwing.rect.midtop) y se añade al grupo de
  disparos xwingLaserGrupo. Observa, también, que en la siguiente línea se
  reproduce el sonido del disparo.
  Hay otra comprobación en la cola de eventos, como habrás visto. Queremos que, en
  cuanto el jugador deje de pulsar una tecla, su nave deje de moverse. Para ello, miramos
  si se ha producido el evento correspondiente (KEYUP) y en tal caso se ponen las
  velocidades de la nave del protagonista a cero para que se pare. Fíjate en la notación;
  es un atajo para dar valores a varias variables a la vez (de hecho, por si quieres saber
  qué es lo que verdaderamente ocurre, hay implícitos unos paréntesis que Python
  interpreta asignando a la tupla de la izquierda los valores de la tupla de la
  derecha...)
  A continuación pasamos a gestionar el movimiento de la nave mirando las pulsaciones
  de la tecla del cursor. Esta vez (aunque también podríamos haberlo hecho dentro de la
  cola de eventos) vamos a usar el segundo método; almacenamos el estado del teclado
  en la variable teclasPulsadas. La ventaja de esta aproximación es que detecta la
  pulsación de varias teclas a la vez (y, por lo tanto, la nave se puede mover en
  diagonal). El resto de esta parte es autoevidente; si se pulsa la tecla del cursor
  izquierdo, la velocidad de la nave se modifica para moverla 4 pixeles hacia la izquierda.
  Y con las otras direcciones trabajamos de manera similar.
  En las siguientes líneas creamos, si se dan las condiciones adecuadas, una nueva nave
  enemiga. El proceso lo hemos contado antes. Se trata de llevar un contador,
  intervaloEnemigos, incrementarlo en cada fotograma y cuando llega a 200 (ese
  número se puede cambiar para conseguir que los enemigos salgan con mayor o menor
  frecuencia) crear una nave, resetear el contador y vuelta a empezar. Observa el código
  de creación, tiefighterGrupo.add( TIEFighter( 320 ) ), ya que de nuevo es un 2
  en 1; se genera un sprite TIEFighter en la posición de coordenada horizontal 320
  (fíjate en la definición del sprite) y se añade al grupo tiefighterGrupo. ¿No es otra
  vez más de lo mismo?
  Pasamos luego a la parte de actualizar la situación de todos los sprites. La forma de
  hacerlo es la típica; llamando a la función miembro update() de todos los grupos
  de sprites que tenemos en el juego.
  Hay que hacer algo más antes de dibujar en pantalla. Tendremos que mirar si se ha
  producido algún impacto de nuestros disparos. A fin de cuentas, ese es el objetivo del
  juego. Hemos usado la función pygame.sprite.groupcollide(). Documentación:


       groupcollide
       Encuentra todos los sprites que colisionan entre dos grupos.

       pygame.sprite.groupcollide(group1, group2, dokill1, dokill2): return
       Sprite_dict


       Esta función encontrará intersecciones entre todos los sprites de dos grupos. Las
       intersecciones se determinan comparando los atributos Sprite.rect de cada Sprite.
       Cada sprite dentro del grupo group1 se agrega al diccionario de retorno como clave. El valor
       de cada elemento será una lista de los sprites del grupo group2 que colisionan con el
       primero.
       Si algunos de los argumentos dokill vale True, se eliminaran los sprites en colisión de sus
       respectivos grupos.



PÁGINA 7 DE 13
                                    
                          CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                        
                       CURSO: 1º BACHILLERATO




  Puedes ver que tiene 4 argumentos y devuelve como resultado un diccionario que
  contiene los sprites del grupo indicado en segundo lugar asociados con los
  sprites del primer grupo con los que ha habido colisión. De esta manera, para ver
  a qué naves enemigas hemos dado, invocamos a esta función así:

  pygame.sprite.groupcollide( tiefighterGrupo, xwingLaserGrupo, 1, 1)

  Los otros dos argumentos de la función (de nuevo, fíjate en la documentación) a los
  que hemos dado valores 1 (eso en Python equivale a True; un valor cero equivale a
  False) representan qué hacer con los sprites involucrados. Los valores True (o lo que
  es lo mismo, 1) indican que se eliminen los sprites del correspondiente grupo
  que entran en colisión. Como queremos que cuando un disparo impacte en una nave
  ambos desaparezcan, hemos puesto ambos valores a 1. Así que el proceso es el
  siguiente; con un bucle for recorremos el diccionario de colisiones y, como
  automáticamente se eliminan los sprites del grupo, simplemente se reproduce el
  sonido de la explosión para cada uno de ellos. Esto funciona correctamente pues, si no
  hay ninguna colisión, el bucle for no tiene lista que recorrer y no hay sonido.
  ¡Por fin hemos llegado al dibujado en pantalla! En los tutoriales anteriores siempre
  borrábamos la surface entera (rellenando toda la ventana con el color de fondo, por
  ejemplo) para dibujar luego los sprites en sus posiciones nuevas. Esto no es muy
  eficiente ya que dibujar toda la pantalla consume más recursos y tiempo que dibujar
  unas cuantas zonas más pequeñas. En la práctica suele hacerse lo que hacemos aquí;
  borrar los sprites de sus posiciones anteriores y dibujarlos en las nuevas.
  La segunda parte ya la sabemos hacer usando la función draw() del grupo. Pero, ¿y la
  primera? La solución es usar la función clear(). Fíjate en el ejemplo:

  xwingGrupo.clear( visor, fondo_imagen )

  Como puedes ver, toma dos argumentos; el primero es la surface donde se va a
  borrar (en este caso la surface que representa la ventana de juego, visor) y el
  segundo es la imagen que se usará en el borrado. PyGame es muy inteligente en
  esto ya que mira en qué posición estaba el sprite y rellena su rect con la porción de
  imagen del correspondiente rect de la imagen de fondo. Genial.

  ¡Ya hemos acabado! Un pygame.display.update() final vuelca el nuevo fotograma,
  ya terminado, en pantalla y la animación está completa.




PÁGINA 8 DE 13
                            
                      CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                             
             CURSO: 1º BACHILLERATO



   # -*- coding: utf-8 -*-
   #-------------------------------------------------------------------
   # Clon de Space Invaders
   # (Basado en un script original de Kevin Harris)
   #-------------------------------------------------------------------

   import random
   import os, pygame
   from pygame.locals import *

   ANCHO = 800
   ALTO = 600

   #-------------------------------------------------------------------
   # Función cargarImagen()
   # ( Carga una imagen desde un archivo, devolviendo el objeto apropiado)
   #-------------------------------------------------------------------

   def cargarImagen( archivo, usarTransparencia = False ):

      lugar = os.path.join( "data", archivo )

      try:
         imagen = pygame.image.load( lugar )
      except pygame.error, mensaje:
         print "No puedo cargar la imagen:", lugar
         raise SystemExit, mensaje

      imagen = imagen.convert()

      if usarTransparencia:
         colorTransparente = imagen.get_at( (0,0) )
         imagen.set_colorkey( colorTransparente )

      return imagen

   #-------------------------------------------------------------------
   # Función cargarSonido()
   # ( Carga un sonido desde un archivo, devolviendo el objeto apropiado)
   #-------------------------------------------------------------------

   def cargarSonido( archivo ):

      class sinSonido:
         def play( self ):
           pass

      if not pygame.mixer or not pygame.mixer.get_init():
         return sinSonido()




PÁGINA 9 DE 13
                                 
            CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                               
            CURSO: 1º BACHILLERATO




      lugar = os.path.join( "data", archivo )

      try:
         sound = pygame.mixer.Sound( lugar )
      except pygame.error, message:
         print "No puedo cargar el sonido:", lugar
         raise SystemExit, message

      return sound

   #-------------------------------------------------------------------
   # Sprite XWing
   # (Nave del Jugador)
   #-------------------------------------------------------------------

   class XWing( pygame.sprite.Sprite ):

      def __init__( self ):
        pygame.sprite.Sprite.__init__( self )
        self.image = cargarImagen( "xwing.bmp", True )
        self.rect = self.image.get_rect()
        self.rect.center = (ANCHO/2,ALTO)
        self.dx = 0
        self.dy = 0

      def update( self ):
        self.rect.move_ip( (self.dx, self.dy) )

         if self.rect.left < 0:
             self.rect.left = 0
         elif self.rect.right > ANCHO:
             self.rect.right = ANCHO

         if self.rect.top <= ALTO/2:
             self.rect.top = ALTO/2
         elif self.rect.bottom >= ALTO:
             self.rect.bottom = ALTO

   #-------------------------------------------------------------------
   # Sprite TIEFighter
   # (Naves enemigas)
   #-------------------------------------------------------------------

   class TIEFighter( pygame.sprite.Sprite ):

      def __init__( self, posx ):
        pygame.sprite.Sprite.__init__( self )
        self.image = cargarImagen( "tie_fighter.bmp", True )




PÁGINA 10 DE 13
                                  
           CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                               
                 CURSO: 1º BACHILLERATO



         self.rect = self.image.get_rect()
         self.rect.centerx = posx
         self.rect.centery = 120
         self.dx = random.randint( -5, 5 )
         self.dy = random.randint( -5, 5 )

      def update( self ):
        self.rect.move_ip( (self.dx, self.dy) )

         if self.rect.left < 0 or self.rect.right > ANCHO:
             self.dx = -(self.dx)

         if self.rect.top < 0 or self.rect.bottom > ALTO/2:
             self.dy = -(self.dy)

         disparar = random.randint( 1, 60 )
         if disparar == 1:
            tiefighterLaserGrupo.add( TIEFighterLaser( self.rect.midbottom ) )
            tiefighterDisparo.play()

   #-------------------------------------------------------------------
   # Sprite XWingLaser
   # (Disparos de jugador)
   #-------------------------------------------------------------------

   class XWingLaser( pygame.sprite.Sprite ):

      def __init__( self, pos ):
        pygame.sprite.Sprite.__init__( self )
        self.image = cargarImagen( "rebel_laser.bmp", True )
        self.rect = self.image.get_rect()
        self.rect.center = pos

      def update( self ):
        if self.rect.bottom <= 0:
            self.kill()
        else:
            self.rect.move_ip( (0,-4) )

   #-------------------------------------------------------------------
   # Sprite TIEFighterLaser
   # (Disparos del enemigo)
   #-------------------------------------------------------------------

   class TIEFighterLaser( pygame.sprite.Sprite ):

      def __init__( self, pos ):
        pygame.sprite.Sprite.__init__( self )
        self.image = cargarImagen( "empire_laser.bmp", True )




PÁGINA 11 DE 13
                                  
                CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                          
                      CURSO: 1º BACHILLERATO



         self.rect = self.image.get_rect()
         self.rect.midtop = pos

      def update( self ):
        if self.rect.bottom >= ALTO:
            self.kill()
        else:
            self.rect.move_ip( (0,4) )

   #-------------------------------------------------------------------
   # Cuerpo Principal del Juego
   #-------------------------------------------------------------------

   random.seed()
   pygame.init()
   visor = pygame.display.set_mode( (ANCHO, ALTO) )
   pygame.display.set_caption( "Star Wars" )

   fondo_imagen = cargarImagen( "background.bmp" )
   visor.blit(fondo_imagen, (0,0))

   explotar = cargarSonido( "explode1.wav" )
   tiefighterDisparo = cargarSonido( "empire_laser.wav" )
   xwingDisparo = cargarSonido( "rebel_laser.wav" )

   xwing = XWing()
   xwingGrupo = pygame.sprite.RenderUpdates(xwing)
   xwingLaserGrupo = pygame.sprite.RenderUpdates()
   tiefighterGrupo = pygame.sprite.RenderUpdates()
   tiefighterGrupo.add( TIEFighter( 150 ) )
   tiefighterGrupo.add( TIEFighter( 400 ) )
   tiefighterGrupo.add( TIEFighter( 650 ) )
   tiefighterLaserGrupo = pygame.sprite.RenderUpdates()

   jugando = True
   intervaloEnemigos = 0
   reloj = pygame.time.Clock()

   while jugando:
     reloj.tick( 60 )

      for event in pygame.event.get():
         if event.type == QUIT:
             jugando = False
         elif event.type == KEYDOWN:
             if event.key == K_ESCAPE:
                 jugando = False
             if event.key == K_SPACE:
                 xwingLaserGrupo.add( XWingLaser( xwing.rect.midtop ) )




PÁGINA 12 DE 13
                             
                     CC: FERNANDO SALAMERO
PROGRAMA: STARWARS
                          
                     CURSO: 1º BACHILLERATO



               xwingDisparo.play()
         elif event.type == KEYUP:
            xwing.dx , xwing.dy = 0 , 0

      teclasPulsadas = pygame.key.get_pressed()
      if teclasPulsadas[K_LEFT]:
          xwing.dx = -4
      if teclasPulsadas[K_RIGHT]:
          xwing.dx = 4
      if teclasPulsadas[K_UP]:
          xwing.dy = -4
      if teclasPulsadas[K_DOWN]:
          xwing.dy = 4

      intervaloEnemigos += 1
      if intervaloEnemigos >= 200:
          tiefighterGrupo.add( TIEFighter( 320 ) )
          intervaloEnemigos = 0

      xwingGrupo.update()
      xwingLaserGrupo.update()
      tiefighterGrupo.update()
      tiefighterLaserGrupo.update()

      for e in pygame.sprite.groupcollide( tiefighterGrupo, xwingLaserGrupo, 1, 1):
         explotar.play()

      tiefighterLaserGrupo.clear( visor, fondo_imagen )
      tiefighterGrupo.clear( visor, fondo_imagen )
      xwingLaserGrupo.clear( visor, fondo_imagen)
      xwingGrupo.clear( visor, fondo_imagen )

      tiefighterLaserGrupo.draw( visor )
      xwingLaserGrupo.draw( visor )
      tiefighterGrupo.draw( visor )
      xwingGrupo.draw( visor )

      pygame.display.update()




PÁGINA 13 DE 13
                             
                   CC: FERNANDO SALAMERO

Contenu connexe

En vedette

En vedette (20)

Programación con Pygame I
Programación con Pygame IProgramación con Pygame I
Programación con Pygame I
 
Programación con Pygame VII
Programación con Pygame VIIProgramación con Pygame VII
Programación con Pygame VII
 
Programación con Pygame III
Programación con Pygame IIIProgramación con Pygame III
Programación con Pygame III
 
Programación con Pygame (II)
Programación con Pygame (II)Programación con Pygame (II)
Programación con Pygame (II)
 
Intro PyGame Capitulo 1
Intro PyGame Capitulo 1Intro PyGame Capitulo 1
Intro PyGame Capitulo 1
 
Intro pygamev2
Intro pygamev2Intro pygamev2
Intro pygamev2
 
Minicurso pygame
Minicurso pygameMinicurso pygame
Minicurso pygame
 
Programación con Pygame VI
Programación con Pygame VIProgramación con Pygame VI
Programación con Pygame VI
 
Pythonic Math
Pythonic MathPythonic Math
Pythonic Math
 
Intro Pygame Capitulo 2
Intro Pygame Capitulo 2Intro Pygame Capitulo 2
Intro Pygame Capitulo 2
 
Programación con Pygame IV
Programación con Pygame IVProgramación con Pygame IV
Programación con Pygame IV
 
Programación con Pygame VIII
Programación con Pygame VIIIProgramación con Pygame VIII
Programación con Pygame VIII
 
Programación con Pygame IX
Programación con Pygame IXProgramación con Pygame IX
Programación con Pygame IX
 
Intro PygameCapitulo 3
Intro PygameCapitulo 3Intro PygameCapitulo 3
Intro PygameCapitulo 3
 
Python (práctica 4)
Python (práctica 4)Python (práctica 4)
Python (práctica 4)
 
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)
 
Programación de Videojuegos con Python y Pilas (X)
Programación de Videojuegos con Python y Pilas (X)Programación de Videojuegos con Python y Pilas (X)
Programación de Videojuegos con Python y Pilas (X)
 
Programación de Videojuegos con Python y Pilas (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)
 
Programación de Videojuegos con Python y Pilas (IX)
Programación de Videojuegos con Python y Pilas (IX)Programación de Videojuegos con Python y Pilas (IX)
Programación de Videojuegos con Python y Pilas (IX)
 
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)
 

Similaire à Programación con Pygame V

Introducción a la programación con action script
Introducción a la programación con action scriptIntroducción a la programación con action script
Introducción a la programación con action script
Lorenɑ' Rodrigueʓ♥
 
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
 
4.2 Programación con action script
4.2 Programación con action script 4.2 Programación con action script
4.2 Programación con action script
German Barajas Ferral
 
Action script 3
Action script 3Action script 3
Action script 3
90000111
 
Thalia castro 1101
Thalia castro 1101Thalia castro 1101
Thalia castro 1101
thalis96
 
4.2 conceptos iniciales de programacion
4.2 conceptos iniciales de programacion4.2 conceptos iniciales de programacion
4.2 conceptos iniciales de programacion
Lupiithaa Martiinez
 
4 2conceptosinicialesdeprogramacion-121003195205-phpapp02
4 2conceptosinicialesdeprogramacion-121003195205-phpapp024 2conceptosinicialesdeprogramacion-121003195205-phpapp02
4 2conceptosinicialesdeprogramacion-121003195205-phpapp02
Carlos Rangel Flores
 
Introducción a la programación con action script
Introducción a la programación con action scriptIntroducción a la programación con action script
Introducción a la programación con action script
Victoria' Worcs
 

Similaire à Programación con Pygame V (20)

Aventura
AventuraAventura
Aventura
 
Introducción a la programación con action script
Introducción a la programación con action scriptIntroducción a la programación con action script
Introducción a la programación con action script
 
Introduccion
IntroduccionIntroduccion
Introduccion
 
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)
 
4.2 Programación con action script
4.2 Programación con action script 4.2 Programación con action script
4.2 Programación con action script
 
Action script 3
Action script 3Action script 3
Action script 3
 
Introduccion
IntroduccionIntroduccion
Introduccion
 
Thalia castro 1101
Thalia castro 1101Thalia castro 1101
Thalia castro 1101
 
4.2 gaem
4.2 gaem4.2 gaem
4.2 gaem
 
Prcaticasfaltantes
PrcaticasfaltantesPrcaticasfaltantes
Prcaticasfaltantes
 
4.2 conceptos iniciales de programacion
4.2 conceptos iniciales de programacion4.2 conceptos iniciales de programacion
4.2 conceptos iniciales de programacion
 
4 2conceptosinicialesdeprogramacion-121003195205-phpapp02
4 2conceptosinicialesdeprogramacion-121003195205-phpapp024 2conceptosinicialesdeprogramacion-121003195205-phpapp02
4 2conceptosinicialesdeprogramacion-121003195205-phpapp02
 
6. revisión y modificación del juego -“space blaster”- Construct 5 - VideoGame
6.  revisión y modificación del juego -“space blaster”- Construct 5 - VideoGame6.  revisión y modificación del juego -“space blaster”- Construct 5 - VideoGame
6. revisión y modificación del juego -“space blaster”- Construct 5 - VideoGame
 
4.2docx
4.2docx4.2docx
4.2docx
 
Introducción a la programación con action script
Introducción a la programación con action scriptIntroducción a la programación con action script
Introducción a la programación con action script
 
4.2
4.24.2
4.2
 
Jhonny
JhonnyJhonny
Jhonny
 
Xna game studio presentación 02
Xna game studio   presentación 02Xna game studio   presentación 02
Xna game studio presentación 02
 
4.2
4.24.2
4.2
 
Introduccion actionscript
Introduccion actionscriptIntroduccion actionscript
Introduccion actionscript
 

Plus de Fernando Salamero

Plus de Fernando Salamero (17)

(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
 
(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
 
(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
 
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
 
Programación de Videojuegos con Python y Pilas (II)
Programación de Videojuegos con Python y Pilas (II)Programación de Videojuegos con Python y Pilas (II)
Programación de Videojuegos con Python y Pilas (II)
 
Programación 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 (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)
 
Python básico II
Python básico IIPython básico II
Python básico II
 
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 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
 

Dernier

Criterios ESG: fundamentos, aplicaciones y beneficios
Criterios ESG: fundamentos, aplicaciones y beneficiosCriterios ESG: fundamentos, aplicaciones y beneficios
Criterios ESG: fundamentos, aplicaciones y beneficios
JonathanCovena1
 
La empresa sostenible: Principales Características, Barreras para su Avance y...
La empresa sostenible: Principales Características, Barreras para su Avance y...La empresa sostenible: Principales Características, Barreras para su Avance y...
La empresa sostenible: Principales Características, Barreras para su Avance y...
JonathanCovena1
 
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
El Fortí
 
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdfNUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
UPTAIDELTACHIRA
 
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
RigoTito
 

Dernier (20)

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
 
Caja de herramientas de inteligencia artificial para la academia y la investi...
Caja de herramientas de inteligencia artificial para la academia y la investi...Caja de herramientas de inteligencia artificial para la academia y la investi...
Caja de herramientas de inteligencia artificial para la academia y la investi...
 
Fe contra todo pronóstico. La fe es confianza.
Fe contra todo pronóstico. La fe es confianza.Fe contra todo pronóstico. La fe es confianza.
Fe contra todo pronóstico. La fe es confianza.
 
2024 KIT DE HABILIDADES SOCIOEMOCIONALES.pdf
2024 KIT DE HABILIDADES SOCIOEMOCIONALES.pdf2024 KIT DE HABILIDADES SOCIOEMOCIONALES.pdf
2024 KIT DE HABILIDADES SOCIOEMOCIONALES.pdf
 
Criterios ESG: fundamentos, aplicaciones y beneficios
Criterios ESG: fundamentos, aplicaciones y beneficiosCriterios ESG: fundamentos, aplicaciones y beneficios
Criterios ESG: fundamentos, aplicaciones y beneficios
 
LABERINTOS DE DISCIPLINAS DEL PENTATLÓN OLÍMPICO MODERNO. Por JAVIER SOLIS NO...
LABERINTOS DE DISCIPLINAS DEL PENTATLÓN OLÍMPICO MODERNO. Por JAVIER SOLIS NO...LABERINTOS DE DISCIPLINAS DEL PENTATLÓN OLÍMPICO MODERNO. Por JAVIER SOLIS NO...
LABERINTOS DE DISCIPLINAS DEL PENTATLÓN OLÍMPICO MODERNO. Por JAVIER SOLIS NO...
 
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
 
SELECCIÓN DE LA MUESTRA Y MUESTREO EN INVESTIGACIÓN CUALITATIVA.pdf
SELECCIÓN DE LA MUESTRA Y MUESTREO EN INVESTIGACIÓN CUALITATIVA.pdfSELECCIÓN DE LA MUESTRA Y MUESTREO EN INVESTIGACIÓN CUALITATIVA.pdf
SELECCIÓN DE LA MUESTRA Y MUESTREO EN INVESTIGACIÓN CUALITATIVA.pdf
 
Sesión de clase: Fe contra todo pronóstico
Sesión de clase: Fe contra todo pronósticoSesión de clase: Fe contra todo pronóstico
Sesión de clase: Fe contra todo pronóstico
 
Programacion Anual Matemática5 MPG 2024 Ccesa007.pdf
Programacion Anual Matemática5    MPG 2024  Ccesa007.pdfProgramacion Anual Matemática5    MPG 2024  Ccesa007.pdf
Programacion Anual Matemática5 MPG 2024 Ccesa007.pdf
 
SESION DE PERSONAL SOCIAL. La convivencia en familia 22-04-24 -.doc
SESION DE PERSONAL SOCIAL.  La convivencia en familia 22-04-24  -.docSESION DE PERSONAL SOCIAL.  La convivencia en familia 22-04-24  -.doc
SESION DE PERSONAL SOCIAL. La convivencia en familia 22-04-24 -.doc
 
ACTIVIDAD DIA DE LA MADRE FICHA DE TRABAJO
ACTIVIDAD DIA DE LA MADRE FICHA DE TRABAJOACTIVIDAD DIA DE LA MADRE FICHA DE TRABAJO
ACTIVIDAD DIA DE LA MADRE FICHA DE TRABAJO
 
La empresa sostenible: Principales Características, Barreras para su Avance y...
La empresa sostenible: Principales Características, Barreras para su Avance y...La empresa sostenible: Principales Características, Barreras para su Avance y...
La empresa sostenible: Principales Características, Barreras para su Avance y...
 
Medición del Movimiento Online 2024.pptx
Medición del Movimiento Online 2024.pptxMedición del Movimiento Online 2024.pptx
Medición del Movimiento Online 2024.pptx
 
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
 
Qué es la Inteligencia artificial generativa
Qué es la Inteligencia artificial generativaQué es la Inteligencia artificial generativa
Qué es la Inteligencia artificial generativa
 
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdfNUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
NUEVAS DIAPOSITIVAS POSGRADO Gestion Publica.pdf
 
TIPOLOGÍA TEXTUAL- EXPOSICIÓN Y ARGUMENTACIÓN.pptx
TIPOLOGÍA TEXTUAL- EXPOSICIÓN Y ARGUMENTACIÓN.pptxTIPOLOGÍA TEXTUAL- EXPOSICIÓN Y ARGUMENTACIÓN.pptx
TIPOLOGÍA TEXTUAL- EXPOSICIÓN Y ARGUMENTACIÓN.pptx
 
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
 
Estrategia de prompts, primeras ideas para su construcción
Estrategia de prompts, primeras ideas para su construcciónEstrategia de prompts, primeras ideas para su construcción
Estrategia de prompts, primeras ideas para su construcción
 

Programación con Pygame V

  • 1. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO StarWars: Un arcade tipo Invaders (Basado en un script original de Kevin Harris) Importación de Librerías Se cargan las librerías habituales, incluyendo random para introducir aleatoriedad en el juego y os para usar direccionamiento de archivos independiente de la plataforma. Definición de Constantes Como quiera que los tamaños de la ventana de juego se usan en varios lugares, es conveniente almacenarlos en variables. En realidad, al no modificarse, más que variables se habla de constantes; para distinguirlas visualmente cuando recorremos un código largo, un método habitual es usar un nombre en mayúsculas. Hemos definido dos: • ANCHO: Anchura de la ventana de juego • ALTO: Altura de la ventana de juego Función cargarImagen() La tarea repetitiva de cargar una imagen desde un archivo y convertirla al formato con el que trabaja PyGame la hemos empaquetado en esta función. La definición posee dos PÁGINA 1 DE 13 CC: FERNANDO SALAMERO
  • 2. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO argumentos, uno obligatorio (el nombre del archivo donde está la imagen) y otro opcional que por defecto se establece como False. Si no utilizamos este segundo argumento cuando llamemos a la función, la imagen generada no tendrá transparencia. Si cuando la llamemos le pasamos True, se usará (fíjate en el código) como color transparente, a la hora de dibujar, el del pixel de la imagen de coordenadas (0,0). Hay varias cosas que comentar: 1. os.path.join() es una función del módulo os que permite usar direcciones de archivos en el disco duro sin pararse a pensar en qué sistema operativo se está. Fíjate que este programa tiene las imágenes y los sonidos en una subcarpeta llamada data. Así que el sonido de explosión explode1.wav se escribiría en MacOS X y en Linux data/explode1.wav mientras que en Windows sería dataexplode1.wav Para no tener que poner ambas y encima tener que comprobar en qué sistema operativo se está ejecutando el juego, os.path.join() es genial, pues nos une el nombre de la carpeta y el archivo correspondientes de la forma adecuada automáticamente. 2. try y except son lo que se denomina gestores de excepciones. Si sabes que todo va a funcionar correctamente no es necesario nada más, pero un buen programador prevé los posibles errores que puedan surgir en la ejecución del programa y los trata adecuadamente. Imagínate que no están las imágenes donde deben estar. El programa terminará con un error que a lo mejor nos es desconocido. Es allí donde entran try y except pues nos permiten detectar el error y hacer algo con ello. Después del try has de poner el código que deseas probar. Si se ejecuta sin problemas, el programa sigue con normalidad; pero si se produce un error, se salta a la instrucción que sigue al except. Allí se gestiona el tipo de error y se puede poner un mensaje, etc. Consulta la documentación de Python para más detalles. Una observación: en nuestro programa se usa la instrucción raise que lanza a su vez un error para indicar a Python que salga del programa (lógicamente, pues no se ha podido cargar la imagen que se quería). En cualquier caso, esto no es estrictamente necesario que aparezca en tus programas. Pero sí conveniente cuando se vuelven largos y complejos. 3. En el caso de que se haya pasado el segundo argumento de la función como True, se procede a asignar la transparencia a la imagen. Para ello se usa la función miembro get_at() que toma un punto como argumento y devuelve su color. Y para usar este color como el color transparente usamos, como vimos en un tutorial anterior, la función miembro set_colorkey(). 4. Finalmente, como queremos que la función devuelva la imagen convertida, hacemos lo propio con un return. Función cargarSonido() Esta función se encarga, en forma análoga a la función anterior, de convertir un archivo de sonido en un objeto Sound. De la misma forma que antes, si no comprobamos ningún PÁGINA 2 DE 13 CC: FERNANDO SALAMERO
  • 3. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO error, la función quedaría muy sencilla; no obstante, vamos a hacer alguna comprobación para aprender alguna técnica nueva: 1. Si hay algún problema con el sistema de sonido del ordenador, el programa no podrá ejecutarse. Antes de que nos dé algún error es mejor detectar este problema y hacer que no se reproduzca ningún sonido y que el resto del juego funcione sin problemas. La forma de hacerlo en el código es curiosa. Se define una nueva clase sinSonido que posee una función play(), como los sonidos. En la definición de esta función se usa simplemente la instrucción pass, es decir, no hacer nada. El objetivo es sencillo; cuando haya problemas con el sonido, se devuelve un objeto de este tipo y así cuando el juego invoque play() no se hará nada. 2. Para comprobar si hay problemas con el sistema de sonido, dentro de un if (como es lógico) miramos si está disponible el módulo pygame.mixer (encargado de gestionar el sonido del juego) y también miramos si se ha inicializado correctamente con pygame.mixer.get_init(). En el caso de que alguno sea False, se devuelve la clase sinSonido del paso anterior. 3. El resto es igual que previamente, pero ahora usando pygame.mixer.Sound() para cargar el archivo de sonido correspondiente. Clase XWing Si eres fan de Star Wars, sabrás que las naves que llevaban los rebeldes se denominaban XWing. La clase XWing va a ser, por lo tanto, la que se encargue del sprite de la nave de nuestro protagonista. Como tal, es una clase derivada de pygame.sprite.Sprite. Vamos a analizar su definición por partes: 1. En __init__() se empieza por inicializar la clase de la que procede (algo, como ya vimos en el último tutorial, necesario). A continuación se definen sus atributos obligatorios, su image y su rect, este último usando el atajo de obtenerlo de la propia imagen gracias a la función get_rect(). La posición en la que se comenzará el sprite viene indicada por center, con lo que se usan las dimensiones de la ventana para situarlo. Finalmente, se definen las variables dx y dy para llevar el control de la velocidad de la nave. 2. Pasemos a update(), quien controla cómo vamos a cambiar la posición de la nave en cada fotograma. La primera instrucción es la ya conocida con move_ip() que nos desplaza al sprite la cantidad indicada por dx y dy. Las siguientes líneas se encargan simplemente, de que la nave no sobrepase los límites de la zona por la que la dejamos mover; horizontalmente hasta los bordes de la ventana y verticalmente hasta la mitad. En tales casos, se fuerza a que la coordenada correspondiente tenga el valor límite y no lo supere. Clase TIEFighter Las naves del enemigo son diferentes, son TIEFighter. Por lo demás, el proceso de definición de esta clase es muy parecido a la anterior con algunos matices: 1. La función __init__() usa ahora otro argumento más, posx, para permitir que las naves enemigas se creen de partida en lugares distintos. Eso lo podemos ver en la línea self.rect.centerx = posx PÁGINA 3 DE 13 CC: FERNANDO SALAMERO
  • 4. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO que nos posiciona la nave de acuerdo a su valor (fíjate de paso que, en el eje vertical, la nave comienza en la coordenada 120, más arriba que la nave del protagonista). Por otra parte, la velocidad del sprite se genera al azar ente -5 y 5 con la instrucción self.dx = random.randint( -5, 5 ) y análogamente para dy. Ésa es la manera de conseguir que cada nave enemiga se mueva de forma distinta. 2. update() es muy parecido también pero ahora, al llegar al borde, se invierte el movimiento de la nave (ya conocemos la técnica que consiste en cambiar de signo su velocidad). Lo que es nuevo es la parte del código que se encarga de generar al azar disparos. La forma de hacerlo es muy típica. Primero hay que evitar que se dispare sin parar, en plan ametralladora; para eso, generamos un número aleatorio entre 1 y 60 y solamente cuando sea 1 se procede a disparar (de lo que se encarga un if). Para crear el disparo, se utilizan dos objetos que se definen más tarde en el código: tiefighterLaserGrupo.add( TIEFighterLaser( self.rect.midbottom ) ) Fíjate bien; en una sola instrucción estamos haciendo, en realidad, dos cosas. En primer lugar se crea un sprite de tipo TIEFighterLaser (es decir, el disparo) y, como veremos en su correspondiente __init__(), se posiciona de partida en la mitad inferior de la nave espacial (de donde visualmente debe de salir el disparo). En segundo lugar, el disparo así creado se añade al grupo tiefighterLaserGrupo con su función miembro add(). Para finalizar, en la última línea tiefighterDisparo.play() se ejecuta el sonido de disparo (veremos luego que tiefighterDisparo es tal sonido). Clase XWingLaser Esta clase define los sprites que representan los disparos de la nave del jugador. Al ser un sprite sencillo su código también lo es. Fíjate que en su __init__() se emplea un argumento añadido para indicar, cuando se cree el objeto correspondiente, en qué posición hay que hacerlo (igual que vimos con las naves del enemigo). Por otra parte, en update(), que es donde implementamos el movimiento, se hace una comprobación con un bloque if. La primero es preguntarse si el disparo ha llegado al borde superior de la ventana (utilizando su rect.bottom; entonces valdría 0), en cuyo caso hay que eliminar el sprite del juego (para que no ocupe memoria y tiempo): self.kill() En efecto, como puedes imaginar la función miembro kill() que posee todo sprite lo elimina por completo. Si no se da esta circunstancia, simplemente hay que mover el disparo hacia arriba usando su rect.move_ip(). Para desplazarlo 4 pixeles,en cada fotograma, hacia arriba, debemos pasar 0 para el incremento en el eje horizontal y -4 para el vertical. PÁGINA 4 DE 13 CC: FERNANDO SALAMERO
  • 5. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO Clase TIEFighterLaser Clase idéntica a la anterior con los matices de que representa a los disparos de los enemigos en lugar de los del jugador; ahora el movimiento es hacia abajo, con lo que el incremento en el movimiento vertical ha de ser de 4 y se comprueba si el disparo sale de la ventana por su borde inferior y no por el superior. De paso observa el detalle de que se emplea para posicionar el sprite su rect.midtop por que luego se ajustará su valor en función del rect.midbottom de la nave enemiga (justo al contrario que con el disparo y la nave del protagonista). ¿Ves por qué? Sólo tienes que pensar de dónde sale el disparo... Cuerpo Principal del Juego Muchas cosas ocurren en esta parte del código, aunque todas siguiendo el esquema habitual: 1. Inicialización A parte del habitual pygame.init() y de crear la Surface del juego (a la que hemos llamado visor) y ponerle título a la ventana, se ha usado random.seed() para garantizar que el juego no se repite cuando se arranca cada vez. En realidad, cuando se carga el módulo random el sistema ya lo realiza automáticamente. He dejado esta instrucción por que si le pasamos un valor numérico concreto, el sistema lo usa como semilla para generar números aleatorios (algo muy interesante si queremos que los diferentes niveles de un juego comiencen siempre de la misma forma, es tu elección). También se carga la imagen de fondo del juego y se sitúa en visor con la función blit() en las coordenadas (0,0), es decir, ocupando toda la ventana (pues tanto imagen como ventana tienen el mismo tamaño). 2. Cargar Sonidos Se cargan y se almacenan en variables los sonidos correspondientes a los disparos del jugador (xwingDisparo), de los enemigos (tiefighterDisparo) y a la explosión de las naves a las que les hemos dado (explotar). 3. Crear los Sprites y los Grupos Tenemos que crear los diferentes tipos de sprites y agruparlos adecuadamente. Para empezar, creamos un sprite de tipo XWing que almacenamos como objeto con el nombre de xwing (gran despliegue de imaginación). En la siguiente línea se crea el grupo de sprites al que va a pertenecer, xwingGrupo (de hecho, será su único miembro). A continuación con xwingLaserGrupo = pygame.sprite.RenderUpdates() creamos un grupo (de momento vacío) que almacenará los diferentes disparos láser de la nave del jugador. Hacemos lo propio con el grupo de sprites de las naves enemigas, esta vez llamado tiefighterGrupo pero, al contrario que con los disparos, creamos y le añadimos al grupo tres naves enemigas. ¿Ves que cada una la creamos y la añadimos en una sola instrucción? Por ejemplo: PÁGINA 5 DE 13 CC: FERNANDO SALAMERO
  • 6. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO tiefighterGrupo.add( TIEFighter( 150 ) ) Crea un sprite de tipo TIEFighter en la posición de coordenada horizontal 150 e inmediatamente lo añade al grupo tiefighterGrupo. Finalmente, creamos también el grupo vacío tiefighterLaserGrupo de los disparos enemigos. 4. Definición de variables de útiles Antes de empezar con el bucle de animación del juego, definimos tres variables que nos serán de utilidad. La variable jugando nos indica que el juego está en activo. La usaremos en el bucle while del juego y bastará poner su valor a False, por lo tanto, para que se salga del bucle y termine el juego. intervaloEnemigos lo vamos a usar para indicar cada cuanto hay que crear un nuevo enemigo. Inicialmente está a 0 y se irá incrementando en cada fotograma. Cuando llegue a un determinado valor (200, como veremos luego), será el momento de crear un enemigo más, poner la variable a 0 y vuelta a empezar. Por último, reloj es un objeto tipo Clock que, como ya vimos en un tutorial anterior, nos permitirá ajustar automáticamente la velocidad de reproducción de la animación del juego. 5. Bucle del Juego Pasamos al bucle principal del juego en el que cada iteración representa un fotograma de la animación. De hecho, la primera línea y el uso de reloj nos indica que la velocidad de reproducción va a ser de 60 fotogramas por segundo. Lo siguiente es comprobar los eventos que hayan ocurrido y nos interesen. Aquí hemos de decidir si hay que terminar el juego, o bien por que el jugador haya hecho click para cerrar la ventana (evento de tipo QUIT) o bien que haya pulsado la tecla escape (evento de tipo KEYDOWN, tecla pulsada K_ESCAPE). Todo esto nos debería resultar familiar. Ahora viene una decisión importante. Cuando miramos las teclas que ha pulsado el jugador para gestionar el juego, lo podemos hacer de dos formas. Una es mirando en la cola de eventos (como acabamos de hacer) y otra es llamando a la función pygame.key.get_pressed() y almacenando el resultado en una variable. El resultado de lo anterior es un diccionario en el que para cada tecla nos devuelve el valor True o False según esté pulsada o no. ¿Qué método usar? Cada uno tiene sus ventajas y sus inconvenientes. El matiz está en que con la función pygame.key.get_pressed() averiguamos si una tecla está pulsada mientras que con la cola de eventos lo averiguamos en el momento en el que se ha pulsado. La diferencia es fundamental. En el movimiento de la nave, nos basta con saber si está pulsada la tecla correspondiente y mover la nave mientras dure la pulsación, pero en los disparos nos interesa el momento mismo en el que se produce dicha pulsación, pues le corresponde un único disparo y entonces necesitamos el método de la cola de eventos (en caso contrario, mientras estuviera la tecla pulsada tendríamos una ráfaga de disparos y el juego sería muy fácil). Dicho esto, podemos entender que se mire, en el evento KEYDOWN si se ha pulsado la tecla espacio (K_SPACE). En caso afirmativo se crea el disparo. ¿Cómo? Con xwingLaserGrupo.add( XWingLaser( xwing.rect.midtop ) ) PÁGINA 6 DE 13 CC: FERNANDO SALAMERO
  • 7. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO creamos en una sola instrucción un sprite tipo XWingLaser que se sitúa justo encima de la nave del jugador y centrada (xwing.rect.midtop) y se añade al grupo de disparos xwingLaserGrupo. Observa, también, que en la siguiente línea se reproduce el sonido del disparo. Hay otra comprobación en la cola de eventos, como habrás visto. Queremos que, en cuanto el jugador deje de pulsar una tecla, su nave deje de moverse. Para ello, miramos si se ha producido el evento correspondiente (KEYUP) y en tal caso se ponen las velocidades de la nave del protagonista a cero para que se pare. Fíjate en la notación; es un atajo para dar valores a varias variables a la vez (de hecho, por si quieres saber qué es lo que verdaderamente ocurre, hay implícitos unos paréntesis que Python interpreta asignando a la tupla de la izquierda los valores de la tupla de la derecha...) A continuación pasamos a gestionar el movimiento de la nave mirando las pulsaciones de la tecla del cursor. Esta vez (aunque también podríamos haberlo hecho dentro de la cola de eventos) vamos a usar el segundo método; almacenamos el estado del teclado en la variable teclasPulsadas. La ventaja de esta aproximación es que detecta la pulsación de varias teclas a la vez (y, por lo tanto, la nave se puede mover en diagonal). El resto de esta parte es autoevidente; si se pulsa la tecla del cursor izquierdo, la velocidad de la nave se modifica para moverla 4 pixeles hacia la izquierda. Y con las otras direcciones trabajamos de manera similar. En las siguientes líneas creamos, si se dan las condiciones adecuadas, una nueva nave enemiga. El proceso lo hemos contado antes. Se trata de llevar un contador, intervaloEnemigos, incrementarlo en cada fotograma y cuando llega a 200 (ese número se puede cambiar para conseguir que los enemigos salgan con mayor o menor frecuencia) crear una nave, resetear el contador y vuelta a empezar. Observa el código de creación, tiefighterGrupo.add( TIEFighter( 320 ) ), ya que de nuevo es un 2 en 1; se genera un sprite TIEFighter en la posición de coordenada horizontal 320 (fíjate en la definición del sprite) y se añade al grupo tiefighterGrupo. ¿No es otra vez más de lo mismo? Pasamos luego a la parte de actualizar la situación de todos los sprites. La forma de hacerlo es la típica; llamando a la función miembro update() de todos los grupos de sprites que tenemos en el juego. Hay que hacer algo más antes de dibujar en pantalla. Tendremos que mirar si se ha producido algún impacto de nuestros disparos. A fin de cuentas, ese es el objetivo del juego. Hemos usado la función pygame.sprite.groupcollide(). Documentación: groupcollide Encuentra todos los sprites que colisionan entre dos grupos. pygame.sprite.groupcollide(group1, group2, dokill1, dokill2): return Sprite_dict Esta función encontrará intersecciones entre todos los sprites de dos grupos. Las intersecciones se determinan comparando los atributos Sprite.rect de cada Sprite. Cada sprite dentro del grupo group1 se agrega al diccionario de retorno como clave. El valor de cada elemento será una lista de los sprites del grupo group2 que colisionan con el primero. Si algunos de los argumentos dokill vale True, se eliminaran los sprites en colisión de sus respectivos grupos. PÁGINA 7 DE 13 CC: FERNANDO SALAMERO
  • 8. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO Puedes ver que tiene 4 argumentos y devuelve como resultado un diccionario que contiene los sprites del grupo indicado en segundo lugar asociados con los sprites del primer grupo con los que ha habido colisión. De esta manera, para ver a qué naves enemigas hemos dado, invocamos a esta función así: pygame.sprite.groupcollide( tiefighterGrupo, xwingLaserGrupo, 1, 1) Los otros dos argumentos de la función (de nuevo, fíjate en la documentación) a los que hemos dado valores 1 (eso en Python equivale a True; un valor cero equivale a False) representan qué hacer con los sprites involucrados. Los valores True (o lo que es lo mismo, 1) indican que se eliminen los sprites del correspondiente grupo que entran en colisión. Como queremos que cuando un disparo impacte en una nave ambos desaparezcan, hemos puesto ambos valores a 1. Así que el proceso es el siguiente; con un bucle for recorremos el diccionario de colisiones y, como automáticamente se eliminan los sprites del grupo, simplemente se reproduce el sonido de la explosión para cada uno de ellos. Esto funciona correctamente pues, si no hay ninguna colisión, el bucle for no tiene lista que recorrer y no hay sonido. ¡Por fin hemos llegado al dibujado en pantalla! En los tutoriales anteriores siempre borrábamos la surface entera (rellenando toda la ventana con el color de fondo, por ejemplo) para dibujar luego los sprites en sus posiciones nuevas. Esto no es muy eficiente ya que dibujar toda la pantalla consume más recursos y tiempo que dibujar unas cuantas zonas más pequeñas. En la práctica suele hacerse lo que hacemos aquí; borrar los sprites de sus posiciones anteriores y dibujarlos en las nuevas. La segunda parte ya la sabemos hacer usando la función draw() del grupo. Pero, ¿y la primera? La solución es usar la función clear(). Fíjate en el ejemplo: xwingGrupo.clear( visor, fondo_imagen ) Como puedes ver, toma dos argumentos; el primero es la surface donde se va a borrar (en este caso la surface que representa la ventana de juego, visor) y el segundo es la imagen que se usará en el borrado. PyGame es muy inteligente en esto ya que mira en qué posición estaba el sprite y rellena su rect con la porción de imagen del correspondiente rect de la imagen de fondo. Genial. ¡Ya hemos acabado! Un pygame.display.update() final vuelca el nuevo fotograma, ya terminado, en pantalla y la animación está completa. PÁGINA 8 DE 13 CC: FERNANDO SALAMERO
  • 9. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO # -*- coding: utf-8 -*- #------------------------------------------------------------------- # Clon de Space Invaders # (Basado en un script original de Kevin Harris) #------------------------------------------------------------------- import random import os, pygame from pygame.locals import * ANCHO = 800 ALTO = 600 #------------------------------------------------------------------- # Función cargarImagen() # ( Carga una imagen desde un archivo, devolviendo el objeto apropiado) #------------------------------------------------------------------- def cargarImagen( archivo, usarTransparencia = False ): lugar = os.path.join( "data", archivo ) try: imagen = pygame.image.load( lugar ) except pygame.error, mensaje: print "No puedo cargar la imagen:", lugar raise SystemExit, mensaje imagen = imagen.convert() if usarTransparencia: colorTransparente = imagen.get_at( (0,0) ) imagen.set_colorkey( colorTransparente ) return imagen #------------------------------------------------------------------- # Función cargarSonido() # ( Carga un sonido desde un archivo, devolviendo el objeto apropiado) #------------------------------------------------------------------- def cargarSonido( archivo ): class sinSonido: def play( self ): pass if not pygame.mixer or not pygame.mixer.get_init(): return sinSonido() PÁGINA 9 DE 13 CC: FERNANDO SALAMERO
  • 10. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO lugar = os.path.join( "data", archivo ) try: sound = pygame.mixer.Sound( lugar ) except pygame.error, message: print "No puedo cargar el sonido:", lugar raise SystemExit, message return sound #------------------------------------------------------------------- # Sprite XWing # (Nave del Jugador) #------------------------------------------------------------------- class XWing( pygame.sprite.Sprite ): def __init__( self ): pygame.sprite.Sprite.__init__( self ) self.image = cargarImagen( "xwing.bmp", True ) self.rect = self.image.get_rect() self.rect.center = (ANCHO/2,ALTO) self.dx = 0 self.dy = 0 def update( self ): self.rect.move_ip( (self.dx, self.dy) ) if self.rect.left < 0: self.rect.left = 0 elif self.rect.right > ANCHO: self.rect.right = ANCHO if self.rect.top <= ALTO/2: self.rect.top = ALTO/2 elif self.rect.bottom >= ALTO: self.rect.bottom = ALTO #------------------------------------------------------------------- # Sprite TIEFighter # (Naves enemigas) #------------------------------------------------------------------- class TIEFighter( pygame.sprite.Sprite ): def __init__( self, posx ): pygame.sprite.Sprite.__init__( self ) self.image = cargarImagen( "tie_fighter.bmp", True ) PÁGINA 10 DE 13 CC: FERNANDO SALAMERO
  • 11. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO self.rect = self.image.get_rect() self.rect.centerx = posx self.rect.centery = 120 self.dx = random.randint( -5, 5 ) self.dy = random.randint( -5, 5 ) def update( self ): self.rect.move_ip( (self.dx, self.dy) ) if self.rect.left < 0 or self.rect.right > ANCHO: self.dx = -(self.dx) if self.rect.top < 0 or self.rect.bottom > ALTO/2: self.dy = -(self.dy) disparar = random.randint( 1, 60 ) if disparar == 1: tiefighterLaserGrupo.add( TIEFighterLaser( self.rect.midbottom ) ) tiefighterDisparo.play() #------------------------------------------------------------------- # Sprite XWingLaser # (Disparos de jugador) #------------------------------------------------------------------- class XWingLaser( pygame.sprite.Sprite ): def __init__( self, pos ): pygame.sprite.Sprite.__init__( self ) self.image = cargarImagen( "rebel_laser.bmp", True ) self.rect = self.image.get_rect() self.rect.center = pos def update( self ): if self.rect.bottom <= 0: self.kill() else: self.rect.move_ip( (0,-4) ) #------------------------------------------------------------------- # Sprite TIEFighterLaser # (Disparos del enemigo) #------------------------------------------------------------------- class TIEFighterLaser( pygame.sprite.Sprite ): def __init__( self, pos ): pygame.sprite.Sprite.__init__( self ) self.image = cargarImagen( "empire_laser.bmp", True ) PÁGINA 11 DE 13 CC: FERNANDO SALAMERO
  • 12. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO self.rect = self.image.get_rect() self.rect.midtop = pos def update( self ): if self.rect.bottom >= ALTO: self.kill() else: self.rect.move_ip( (0,4) ) #------------------------------------------------------------------- # Cuerpo Principal del Juego #------------------------------------------------------------------- random.seed() pygame.init() visor = pygame.display.set_mode( (ANCHO, ALTO) ) pygame.display.set_caption( "Star Wars" ) fondo_imagen = cargarImagen( "background.bmp" ) visor.blit(fondo_imagen, (0,0)) explotar = cargarSonido( "explode1.wav" ) tiefighterDisparo = cargarSonido( "empire_laser.wav" ) xwingDisparo = cargarSonido( "rebel_laser.wav" ) xwing = XWing() xwingGrupo = pygame.sprite.RenderUpdates(xwing) xwingLaserGrupo = pygame.sprite.RenderUpdates() tiefighterGrupo = pygame.sprite.RenderUpdates() tiefighterGrupo.add( TIEFighter( 150 ) ) tiefighterGrupo.add( TIEFighter( 400 ) ) tiefighterGrupo.add( TIEFighter( 650 ) ) tiefighterLaserGrupo = pygame.sprite.RenderUpdates() jugando = True intervaloEnemigos = 0 reloj = pygame.time.Clock() while jugando: reloj.tick( 60 ) for event in pygame.event.get(): if event.type == QUIT: jugando = False elif event.type == KEYDOWN: if event.key == K_ESCAPE: jugando = False if event.key == K_SPACE: xwingLaserGrupo.add( XWingLaser( xwing.rect.midtop ) ) PÁGINA 12 DE 13 CC: FERNANDO SALAMERO
  • 13. PROGRAMA: STARWARS CURSO: 1º BACHILLERATO xwingDisparo.play() elif event.type == KEYUP: xwing.dx , xwing.dy = 0 , 0 teclasPulsadas = pygame.key.get_pressed() if teclasPulsadas[K_LEFT]: xwing.dx = -4 if teclasPulsadas[K_RIGHT]: xwing.dx = 4 if teclasPulsadas[K_UP]: xwing.dy = -4 if teclasPulsadas[K_DOWN]: xwing.dy = 4 intervaloEnemigos += 1 if intervaloEnemigos >= 200: tiefighterGrupo.add( TIEFighter( 320 ) ) intervaloEnemigos = 0 xwingGrupo.update() xwingLaserGrupo.update() tiefighterGrupo.update() tiefighterLaserGrupo.update() for e in pygame.sprite.groupcollide( tiefighterGrupo, xwingLaserGrupo, 1, 1): explotar.play() tiefighterLaserGrupo.clear( visor, fondo_imagen ) tiefighterGrupo.clear( visor, fondo_imagen ) xwingLaserGrupo.clear( visor, fondo_imagen) xwingGrupo.clear( visor, fondo_imagen ) tiefighterLaserGrupo.draw( visor ) xwingLaserGrupo.draw( visor ) tiefighterGrupo.draw( visor ) xwingGrupo.draw( visor ) pygame.display.update() PÁGINA 13 DE 13 CC: FERNANDO SALAMERO