SlideShare una empresa de Scribd logo
1 de 10
Descargar para leer sin conexión
PROGRAMA: AVENTURA
                            
                        CURSO: 1º BACHILLERATO




Aventura: Ficción Interactiva




     (Parte del código de recorte basado en un script original de Tiny Ducks On Wheels)


Introducción
El objetivo del programa es aprender una serie de técnicas y disponer de código que nos
sirva para realizar juegos de ficción interactiva con PyGame, es decir, juegos
conversacionales (del estilo de “The House”) con imágenes. Para ello, el programa se
organiza en torno a tres clases y una función que podéis modificar o ampliar en vuestros
propios programas:
1.    La clase Narrar
      Un objeto de este tipo es el que se utilizar para poner en pantalla la descripción del
      lugar en el que se encuentra el jugador. También puede usarse para responder a sus
      peticiones. Cuando se crea el objeto, hay que proporcionarle una surface (sobre la
      que se dibujará), un rect (que marcará la zona donde ha de dibujarse), un tipo de letra
      y un color (que se emplearán al dibujar el texto) y el color de fondo.
2.    La clase Hablar
      El objeto de este tipo hace las veces del cuadro donde el jugador escribe las acciones
      que desea realizar. Al crearse el objeto, debemos pasarle también una surface y un
      rect, un tipo de letra, su color y el color de fondo.
 PÁGINA 1 DE 10
                                
                       CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                          
                       CURSO: 1º BACHILLERATO

3.   La clase Juego
     Se trata del tipo de objeto más importante del juego, pues representa el status en el
     que se encuentra; localización, acciones... Como allí donde esté el jugador debe
     proporcionársele una descripción del entorno y, además, debe poder decir lo que
     quiere hacer, esta clase está ligada a las clases Narrar y Hablar. En consecuencia,
     cuando se crea uno de estos objetos hay que proporcionarle, una vez más, una surface
     (sobre lo que dibujar), una imagen (que representará el lugar en el que nos
     encontramos), un objeto de tipo Narrar y otro de tipo Hablar.
4.   La función procesar()
     Esta función se encargará de procesar las órdenes del jugador para realizar las
     correspondientes acciones, es decir, es el parser. En un juego completo, aquí está el
     núcleo del desarrollo de la aventura, ya que se usará para tomar objetos, cambiar de
     localización, luchar, etc. Como las acciones dependerán de la situación en la que nos
     encontremos en el juego, cuando se invoca a la función se le ha de pasar como
     argumento un objeto de tipo Juego.




Como quiera que el programa tiene por objetivo aprender la técnica, no es un juego
realmente operativo. Sólo están implementados los comandos “norte”, “sur” y “salir” y sólo
están incluidos dos lugares (y por tanto, dos imágenes).
Veamos el código:




 PÁGINA 2 DE 10
                              
                      CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                           
                       CURSO: 1º BACHILLERATO


Importación de Librerías y Definición de Constantes
Ya de sobras conocido; las librerías habituales, la inicialización de PyGame, la creación del
objeto visor con la surface del juego y las declaraciones de los colores que vamos a usar
con los textos y el diálogo.


Clase JUEGO
1.   En el constructor de la clase, es decir, la función __init__(), lo que hacemos es
     almacenar como atributos los argumentos que se le pasan para que la clase los pueda
     utilizar posteriormente cuando se desee. Estos atributos (a los que se accede como
     sabemos, con self.nombre_del_atributo) son surface, image (hemos usado image y
     no imagen, como nombre, por similitud a la clase pygame.sprite.Sprite), narrar y
     hablar. Ya hemos explicado más arriba su significado.
2.   La función update() se encarga de actualizar y dibujar en pantalla la situación en la
     que nos encontramos en el juego (observa, de nuevo, que hemos elegido un nombre
     familiar...). Fíjate el orden en el que lo hacemos. Primero se dibuja la imagen de fondo
     (‘el paisaje’). A continuación se llama al método update() del objeto narrar para
     que dibuje sobre el paisaje lo que ocurre en el juego. Finalmente se llama a la función
     escuchar() del propio objeto para que, como veremos enseguida, se esté atento al
     teclado y se procesen las teclas que se vayan pulsando.
3.   escuchar() se encarga de ir escribiendo en pantalla lo que se escribe hasta que se
     pulsa la tecla return (K_RETURN). La técnica es interesante, pues al contrario que
     con los programas escritos para la linea de comandos, en las surfaces de PyGame no
     se puede escribir directamente al estilo del conocido raw_input(). Veamos cómo se
     ha implementado:
     Lo primero es calcular cuántas letras nos caben en el cuadrado de texto que hará las
     veces de diálogo. Veremos en breve que el objeto hablar tiene un atributo de tipo
     Rect (que llamaremos rect) que indica la zona en la que se va a poner en pantalla. Así
     que podemos averiguar su anchura total en pixeles con hablar.rect.w . Si lo
     dividimos por la anchura de una letra típica, como la letra ‘a’, sabremos cuántas letras
     nos van a caber. Afortunadamente, el objeto de tipo hablar tendrá también un
     atributo de tipo Font (llamado tipoLetra) que posee (mira la documentación) una
     función miembro ( size() ) que nos da la anchura en pixeles de un carácter.
     ¡Estupendo! Almacenaremos cuántas letras nos caben en la variable maximo. Es más
     fácil verlo que contarlo:

     maximo = self.hablar.rect.w / self.hablar.tipoLetra.size('a')[0]

     (el [0] del final es por que, como habrás visto en la documentación, la función size()
     nos devuelve una tupla con la anchura y la altura, así que nos interesa el primer
     elemento).

     Probablemente, si has probado a escribir texto con PyGame habrás tenido problemas
     con los acentos o con los caracteres no anglosajones como ‘ñ’. Para que se muestren
     correctamente, necesitamos pasarle los textos con codificación unicode. No te
     preocupes; basta añadirle una u como prefijo a una cadena de texto para que se
     considere como unicode. Es por eso por lo que se ha escrito

     self.hablar.frase = u''

 PÁGINA 3 DE 10
                               
                      CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                           
                       CURSO: 1º BACHILLERATO



     para inicializar una cadena de texto (en blanco) a la que se añadirán las teclas que se
     vayan pulsando. De nuevo, frase será un atributo del objeto hablar que se encargará
     de memorizar las órdenes que se vayan dando en el juego.
     Lo siguiente es dibujar el cuadrado que enmarca la zona donde se escribirán nuestras
     ordenes. La función cuadrado() del objeto hablar se encargará de ello. Naturalmente,
     si queremos que se muestre inmediatamente en pantalla, tendremos que invocar a
     pygame.display.update().
     Vamos a la parte final. Necesitamos un bucle que vaya capturando las teclas pulsadas y
     que termine cuando se pulse return. La variable booleana hablando nos ayudará en
     la tarea; dentro del bucle, miramos la cola de eventos de la forma habitual y si la
     tecla pulsada es K_RETURN, hablando se pone a False, el bucle acabará y se
     saldrá de la función escuchar().
     Si la tecla pulsada es otra, querremos escribirla en pantalla. Afortunadamente,
     PyGame dispone de evento.unicode que nos da, precisamente, el texto de la tecla
     pulsada en codificación unicode. La función que se encargará de usar esta pulsación
     para escribir en pantalla será la función update() del objeto hablar:

     self.hablar.update(evento.unicode)

     Un matiz. Si la tecla pulsada es la de borrar (K_BACKSPACE), querremos que se
     elimine la última tecla pulsada, de allí la instrucción

     self.hablar.frase = self.hablar.frase[:-1]

     que hace precisamente eso (y no hay que pasarle ningún valor para dibujar). Además,
     hay que controlar que el número de teclas pulsadas no superen el máximo deseado (en
     caso contrario, el texto se saldría del cuadro), lo que se consigue mirando si
     len(self.hablar.frase) < maximo.


Clase Hablar
Se encarga de mostrar y almacenar las órdenes del jugador.
1.   __init__(), como es habitual, guarda como atributos los valores que se pasan al
     objeto cuando se crea. Además, se definen dos atributos más: margen marca el
     tamaño del margen, ya que si el texto comienza a escribirse justo en el borde del
     cuadro queda poco elegante; y frase contendrá, como hemos visto, lo que escribe el
     jugador.
2.   La función cuadrado() realza la zona en la que se va a escribir. Para que no tape la
     parte de la imagen de fondo que tiene detrás tendremos que aplicarle transparencia.
     ¿Cómo hacerlo? Primero creamos una surface del tamaño del rect del objeto que
     llamamos cuadrado. Indicamos que vamos a usar transparencia con el ya conocido
     convert_alpha(). ¿Cuánta transparencia? Eso se indica con set_alpha() ; cuanto
     menor sea el valor que le pasemos, tanto más transparente será. Finalmente, pintamos
     el cuadrado entero del color deseado con fill() y se dibuja el resultado sobre la
     surface que se ha pasado al objeto (típicamente, nuestro visor).
3.   Al método update(), si recordamos lo que hemos visto en la clase Juego, le pasamos
     el valor de evento.unicode (la tecla pulsada). Ese parámetro lo hemos llamado tecla
     en la implementación de la función. El objetivo es añadir dicha tecla a la variable frase
     y dibujar el resultado.
 PÁGINA 4 DE 10
                               
                      CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                            
                        CURSO: 1º BACHILLERATO

     Las primeras dos líneas posicionan dónde va a escribirse, dejando el margen
     pertinente. A continuación se añade a frase el valor de tecla (todo está en unicode,
     así que es correcto), se dibuja el marco semitransparente, se dibuja el texto y se
     actualiza la pantalla para que se muestre. ¡Muy bien!


Clase Narrar
Muestra la descripción del lugar donde se encuentra el jugador o cualquier otro mensaje
que se desee como respuesta a una acción, a través de su atributo texto. La idea es hacerlo
de forma similar a la clase anterior pero ahora el problema es distinto. El texto entero ya lo
tenemos pero, por contra, puede ser muy largo y ocupar muchas líneas. La clase se
encargará de ajustar automáticamente el texto al tamaño disponible.
1.   __init__() almacena, como es habitual, los parámetros con los que se crea el objeto
     en atributos propios (para usarlos posteriormente). Hay un añadido, como ya hemos
     comentado, texto.
2.   cortaTexto() es un método que toma como argumento un número que representa el
     tamaño máximo en pixeles que puede ocupar una línea de texto. El objetivo de la
     función es, partiendo del texto almacenado en texto, dividirlo en una lista de líneas
     que respeten el ancho dado. Con ello se consigue que sea cual sea el valor de texto, se
     ajuste y quepa dentro de la zona donde se va a escribir.
     Para realizarlo, y usando nuestra vieja amiga split(), el texto se divide en una lista de
     líneas de partida (para conservar los puntos y aparte que pudiera tener):

     lineas = self.texto.split("n")

     (el código especial ‘n’ es la marca de nueva línea en Linux). A continuación creamos
     una lista vacía, resultado, en donde se irán añadiendo las lineas con el tamaño
     correcto.
     El resto del trabajo se realiza con un bucle for que recorre todas las lineas anteriores.
     Para cada una de ellas, palabras contiene su lista de palabras (de nuevo usando
     split()). La idea es ir añadiendo palabras, calcular cuanto tamaño tiene cada una, y si
     no se supera el tamaño máximo ir a por la siguiente. En el momento en el que se
     supere dicho tope, se cambia de linea (es decir, se añade la línea a la lista y se
     empiezan a mirar las siguientes palabras). Intenta seguir el proceso. Ten en cuenta que
     se calcula el ancho en pixeles de un texto con size(), que se añaden elementos a la lista
     con el método append() de los objetos list, y que para concatenar textos se usa el
     método join() de los objetos str. En cualquier caso, la función termina devolviendo
     como valor de salida a resultado, la lista de líneas deseada.
3.   La función update() toma como único argumento un número, margen, cuyo
     significado es evidente por el nombre. Comenzamos calculando la posición en la que
     situar el texto horizontalmente, dejando el margen y obteniendo la lista de líneas que
     se van a escribir, lineas, llamando al método cortaTexto() que hemos visto hace un
     momento. Observa que se ha tenido en cuenta también el margen para indicar el
     máximo tamaño disponible (se resta dos veces, contando ambos lados).
     Para centrar el texto verticalmente, necesitamos saber cuanto ocupan las líneas. En
     nuestro auxilio viene el método get_linesize() de los objetos Font. Nos devuelve la
     altura en pixeles que ocupa una linea de texto con ese tipo de letra. Una vez conocido,
     para conseguir que el texto quede en la parte central de la zona de impresión,
     calculamos su coordenada vertical así:

 PÁGINA 5 DE 10
                                
                      CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                            
                        CURSO: 1º BACHILLERATO

    posy = self.rect.top + (self.rect.h - alturaLinea * len(lineas)) / 2

    (observa que a la altura de la zona que ocupa el texto, se le resta la altura total de todas
    las líneas y el resultado se divide por dos para que el margen sea el mismo por arriba
    que por abajo; probablemente necesitarás hacerte un dibujo para entenderlo).
    Ya podemos pasar a dibujar. Primero, de forma similar a como hacía la función
    cuadrado() en la clase Hablar, dibujamos el cuadrado de fondo semitransparente.
    A continuación, recorremos todas las líneas del texto y las dibujamos. Fíjate que
    después de dibujar una línea, se añade a posy el valor de la altura de la línea calculada
    para que la siguiente se dibuje debajo, en el lugar correcto. Y, finalmente, se vuelca
    todo en pantalla para que lo visualice el jugador.


función procesar()
En un juego real esta función sería bastante más complicada y extensa y ésta es la razón
por lo que se implementa como una función externa y no como un método más de la
clase Juego. De hecho, para poder modificarlo, juego se pasa como argumento a la
función.
Nuestro procesar() simplemente comprueba cuál es la imagen de fondo actual (es decir,
juego.image) para actuar convenientemente. Si se trata de castillo sólo haremos caso
cuando la frase que ha escrito el jugador sea ‘norte’; entonces cambiamos la imagen a
patio y la descripción a frase2. Algo similar ocurre cuando la imagen actual es patio; la
única salida es al sur y sólo se obedece en tal caso. Por otra parte, si el jugador escribe
‘salir’ el juego debe terminar.
Lo dicho, en un juego serio aquí se harían muchas comprobaciones. Además, nadie nos
impide añadir más atributos a la clase Juego para que se almacene más información sobre
el jugador (objetos que lleva, salud, armas, etc). Recuerda que en el juego ‘TheHouse’, el
parser era bastante largo y usaba bastantes variables de estado.



Cuerpo Principal del Juego
Llegamos al último bloque del juego. Para empezar, cargamos las imágenes de fondo
castillo y patio y definimos las descripciones de ambas localizaciones, frase1 y frase2.
En un juego completo, lo ideal sería una lista o un diccionario y no variables sueltas.
Continuamos definiendo los tipos de letra para la descripción de los lugares y las
situaciones (letraNarrar) y para el diálogo con el ordenador (letraHablar). También se
definen las zonas donde se van a mostrar con sendos Rect (dondeTexto y
dondeComando).
Justo antes del bucle del juego se crean los objetos que lo controlan; narrar, hablar y
juego. En la creación de este último se usan los dos anteriores. Observa que para
inicializar el juego necesitamos proporcionarle los datos de por donde empezar. La imagen
de fondo se pasa al crearlo (castillo) y la descripción del lugar se pone a mano con

narrar.texto = frase1

Finalmente, el bucle del juego realiza una y otra vez las dos tareas obvias; mostrar en
pantalla la situación actualizada y esperar las acciones del usuario con juego.update() y
procesar lo que haya introducido el jugador con procesar(juego).
 PÁGINA 6 DE 10
                                
                       CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                            
                     CURSO: 1º BACHILLERATO



   # -*- coding: utf-8 -*-

   #-------------------------------------------------------------------
   # aventura.py
   # (cortaTexto basado en un script de Tiny Ducks On Wheels)
   #-------------------------------------------------------------------


   import pygame, sys
   from pygame.locals import *

   AMARILLO = (200,200,0)
   BLANCO = (200,200,200)
   VERDE = (0,100,0)
   LILA = (50,0,50)

   pygame.init()

   visor = pygame.display.set_mode((800,600))

   #-------------------------------------------------------------------
   # Clase Juego
   # (Clase principal que coordina las demás)
   #-------------------------------------------------------------------

   class Juego:
      def __init__(self, surface, imagen, narrar, hablar):
        self.surface = surface
        self.image = imagen
        self.narrar = narrar
        self.hablar = hablar

      def update(self):
        self.surface.blit(self.image, (0,0))
        self.narrar.update(10)
        self.escuchar()

      def escuchar(self):
        maximo = self.hablar.rect.w / self.hablar.tipoLetra.size('a')[0]
        self.hablar.frase = u''
        self.hablar.cuadrado()
        pygame.display.update()
        hablando = True
        while hablando:
           for evento in pygame.event.get():
              if evento.type == QUIT:
                  pygame.quit()
                  sys.exit()
              elif evento.type == KEYDOWN:




PÁGINA 7 DE 10
                                
                    CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                             
                        CURSO: 1º BACHILLERATO




                  if evento.key == K_RETURN:
                      hablando = False
                  elif evento.key == K_BACKSPACE:
                      self.hablar.frase = self.hablar.frase[:-1]
                      self.hablar.update(u'')
                  elif len(self.hablar.frase) < maximo:
                      self.hablar.update(evento.unicode)

   #-------------------------------------------------------------------
   # Clase Hablar
   # ( Gestiona ka introducción de texto del usaurio)
   #-------------------------------------------------------------------

   class Hablar:
      def __init__(self, surface, rect, tipoLetra, colorTexto, colorFondo):
        self.surface = surface
        self.rect = rect
        self.tipoLetra = tipoLetra
        self.color = colorTexto
        self.colorFondo = colorFondo
        self.margen = 10
        self.frase = u''

      def cuadrado(self):
        cuadrado = pygame.Surface((self.rect.w,self.rect.h))
        cuadrado.convert_alpha()
        cuadrado.set_alpha(200)
        cuadrado.fill(self.colorFondo)
        self.surface.blit(cuadrado, self.rect.topleft)

      def update(self, tecla):
        x = self.rect.left + self.margen
        y = self.rect.top + self.margen
        self.frase += tecla
        self.cuadrado()
        self.surface.blit(self.tipoLetra.render(self.frase, True, self.color), (x,y))
        pygame.display.update()

   #-------------------------------------------------------------------
   # Clase Narrar
   # ( Muestra las descripciones de las situaciones)
   #-------------------------------------------------------------------

   class Narrar:
      def __init__(self, surface, rect, tipoLetra, colorTexto, colorFondo):
        self.surface = surface
        self.rect = rect
        self.tipoLetra = tipoLetra
        self.color = colorTexto




PÁGINA 8 DE 10
                                 
                       CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                            
                        CURSO: 1º BACHILLERATO



         self.colorFondo = colorFondo
         self.texto = u''

      def cortaTexto(self, anchoTotal):
        lineas = self.texto.split("n")
        resultado = []
        for linea in lineas:
           palabras = linea.split(" ")
           comienzo = 0

            i=0
            while i < len(palabras):
              ancho = self.tipoLetra.size(" ".join(palabras[comienzo:i+1]))[0]
              if ancho > anchoTotal:
                  resultado.append(" ".join(palabras[comienzo:i]))
                  comienzo = i
                  i -= 1
              elif i is len(palabras) - 1:
                  resultado.append(" ".join(palabras[comienzo:i + 1]))

                  i += 1

         return resultado

      def update(self, margen):
        posx = self.rect.left + margen
        lineas = self.cortaTexto(self.rect.width - 2*margen)
        alturaLinea = self.tipoLetra.get_linesize()
        posy = self.rect.top + (self.rect.h - alturaLinea * len(lineas)) / 2
        cuadrado = pygame.Surface((self.rect.w, self.rect.h))
        cuadrado.convert_alpha()
        cuadrado.set_alpha(200)
        cuadrado.fill(self.colorFondo)
        self.surface.blit(cuadrado, (self.rect.left,self.rect.top))
        for linea in lineas:
           self.surface.blit(self.tipoLetra.render(linea, True, self.color), (posx, posy))
           posy = posy + alturaLinea
        pygame.display.update()

   #-------------------------------------------------------------------
   # Función procesar()
   # ( El parser del juego)
   #-------------------------------------------------------------------

   def procesar(juego):
     if juego.image == castillo and juego.hablar.frase == 'norte':
         juego.image = patio
         juego.narrar.texto = frase2
     elif juego.image == patio and juego.hablar.frase == 'sur':




PÁGINA 9 DE 10
                                
                       CC: FERNANDO SALAMERO
PROGRAMA: AVENTURA
                         
                     CURSO: 1º BACHILLERATO



         juego.image = castillo
         juego.narrar.texto = frase1
      elif juego.hablar.frase == 'salir':
         pygame.quit()
         sys.exit()

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

   castillo = pygame.image.load('castillo.jpg').convert()
   patio = pygame.image.load('patio.png').convert()
   frase1 = u'Abres los Ojos...nNo recuerdas nada. ¿Dónde estás? Al norte hay una
   puerta.'
   frase2 = u'Un patio se abre ante ti. Al sur está la puerta que has traspasado.'

   letraHablar = pygame.font.Font('Grandezza.ttf', 24)
   letraNarrar = pygame.font.Font('Adolphus.ttf', 24)
   dondeTexto = pygame.Rect((100,300,600, 200))
   dondeComando = pygame.Rect((100,550,600,40))
   narrar = Narrar(visor, dondeTexto, letraNarrar, AMARILLO, LILA)
   hablar = Hablar(visor, dondeComando, letraHablar, BLANCO, VERDE)
   juego = Juego(visor, castillo, narrar, hablar)
   narrar.texto = frase1


   while True:
     juego.update()
     procesar(juego)




PÁGINA 10 DE 10
                            
                   CC: FERNANDO SALAMERO

Más contenido relacionado

La actualidad más candente

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
 
Introduccion Scratch
Introduccion ScratchIntroduccion Scratch
Introduccion Scratchmiguelmaneu78
 
Tutorial game maker
Tutorial game makerTutorial game maker
Tutorial game makerJoserichi
 
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
 
Guía paso a paso curso scratch (Parte I - 2016)
Guía paso a paso curso scratch (Parte I - 2016)Guía paso a paso curso scratch (Parte I - 2016)
Guía paso a paso curso scratch (Parte I - 2016)Agneta Gallardo
 
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 scratch
Programación scratchProgramación scratch
Programación scratchLuis Duran
 
Makeblock bloques de_programacion
Makeblock bloques de_programacionMakeblock bloques de_programacion
Makeblock bloques de_programacionJoesclajo Garcia
 
Guía Scratch.
Guía Scratch.Guía Scratch.
Guía Scratch.angelguiza
 
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
 
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
 
Tutorial manejo de_scratch
Tutorial manejo de_scratchTutorial manejo de_scratch
Tutorial manejo de_scratchFredy Guerrero
 

La actualidad más candente (18)

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)
 
Game Maker Primera parte
Game Maker Primera parteGame Maker Primera parte
Game Maker Primera parte
 
Manual Scratch
Manual ScratchManual Scratch
Manual Scratch
 
Introduccion Scratch
Introduccion ScratchIntroduccion Scratch
Introduccion Scratch
 
Tutorial game maker
Tutorial game makerTutorial game maker
Tutorial game maker
 
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)
 
Tutorial de Scratch
Tutorial de ScratchTutorial de Scratch
Tutorial de Scratch
 
Guía paso a paso curso scratch (Parte I - 2016)
Guía paso a paso curso scratch (Parte I - 2016)Guía paso a paso curso scratch (Parte I - 2016)
Guía paso a paso curso scratch (Parte I - 2016)
 
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 scratch
Programación scratchProgramación scratch
Programación scratch
 
Makeblock bloques de_programacion
Makeblock bloques de_programacionMakeblock bloques de_programacion
Makeblock bloques de_programacion
 
Manual finale 97
Manual finale 97Manual finale 97
Manual finale 97
 
Guía Scratch.
Guía Scratch.Guía Scratch.
Guía Scratch.
 
Obradoiro LIM Cangas 2012
Obradoiro LIM Cangas 2012Obradoiro LIM Cangas 2012
Obradoiro LIM Cangas 2012
 
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
 
Flash Duban
Flash DubanFlash Duban
Flash Duban
 
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)
 
Tutorial manejo de_scratch
Tutorial manejo de_scratchTutorial manejo de_scratch
Tutorial manejo de_scratch
 

Similar a Aventura

4manipularbotones 121006192501-phpapp02 (1)
4manipularbotones 121006192501-phpapp02 (1)4manipularbotones 121006192501-phpapp02 (1)
4manipularbotones 121006192501-phpapp02 (1)Jose Joney Vargas Castro
 
Practicas: "MICROSOFT WORD"
Practicas: "MICROSOFT WORD"Practicas: "MICROSOFT WORD"
Practicas: "MICROSOFT WORD"'Aroo Juárez
 
Unidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseñoUnidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseñojosselinecamargo
 
Tutorial pixel art
Tutorial pixel artTutorial pixel art
Tutorial pixel artY-Green
 
Lenguaje de programación logo
Lenguaje de programación logoLenguaje de programación logo
Lenguaje de programación logoAracelyLeyton
 
5°-grado-Animacion-con-dialogos-usando-Scratch.pdf
5°-grado-Animacion-con-dialogos-usando-Scratch.pdf5°-grado-Animacion-con-dialogos-usando-Scratch.pdf
5°-grado-Animacion-con-dialogos-usando-Scratch.pdfssuser42eafa
 
TALLER SCRATCH 1º ó 2º ESO (1).pdf
TALLER SCRATCH 1º ó 2º ESO (1).pdfTALLER SCRATCH 1º ó 2º ESO (1).pdf
TALLER SCRATCH 1º ó 2º ESO (1).pdfsergiomaureira4
 
Actividad no.1 (Visual Basic)
Actividad no.1 (Visual Basic)Actividad no.1 (Visual Basic)
Actividad no.1 (Visual Basic)Jose Torres
 
Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)
Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)
Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)Josseline Camargo D'l Angel
 
Unidad 2 Manipular el Dibujo Utilizando Herramientas de Diseño
Unidad 2 Manipular el Dibujo Utilizando Herramientas de DiseñoUnidad 2 Manipular el Dibujo Utilizando Herramientas de Diseño
Unidad 2 Manipular el Dibujo Utilizando Herramientas de DiseñoCesar Govea Rodriguez
 
Unidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseñoUnidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseñoAna' Patlan
 
Davinson clavijo castillo
Davinson clavijo castilloDavinson clavijo castillo
Davinson clavijo castillodavinson1
 

Similar a Aventura (20)

Programación con Pygame V
Programación con Pygame VProgramación con Pygame V
Programación con Pygame V
 
4 manipular botones
4 manipular botones4 manipular botones
4 manipular botones
 
4manipularbotones 121006192501-phpapp02 (1)
4manipularbotones 121006192501-phpapp02 (1)4manipularbotones 121006192501-phpapp02 (1)
4manipularbotones 121006192501-phpapp02 (1)
 
Practicas: "MICROSOFT WORD"
Practicas: "MICROSOFT WORD"Practicas: "MICROSOFT WORD"
Practicas: "MICROSOFT WORD"
 
Unidad 2
Unidad 2Unidad 2
Unidad 2
 
GAME MAKER
GAME MAKERGAME MAKER
GAME MAKER
 
Scratch informacion
Scratch informacionScratch informacion
Scratch informacion
 
Unidad 4
Unidad 4Unidad 4
Unidad 4
 
Unidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseñoUnidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseño
 
Tutorial pixel art
Tutorial pixel artTutorial pixel art
Tutorial pixel art
 
Lenguaje de programación logo
Lenguaje de programación logoLenguaje de programación logo
Lenguaje de programación logo
 
Intro pygamev2
Intro pygamev2Intro pygamev2
Intro pygamev2
 
5°-grado-Animacion-con-dialogos-usando-Scratch.pdf
5°-grado-Animacion-con-dialogos-usando-Scratch.pdf5°-grado-Animacion-con-dialogos-usando-Scratch.pdf
5°-grado-Animacion-con-dialogos-usando-Scratch.pdf
 
Unida 2
Unida 2Unida 2
Unida 2
 
TALLER SCRATCH 1º ó 2º ESO (1).pdf
TALLER SCRATCH 1º ó 2º ESO (1).pdfTALLER SCRATCH 1º ó 2º ESO (1).pdf
TALLER SCRATCH 1º ó 2º ESO (1).pdf
 
Actividad no.1 (Visual Basic)
Actividad no.1 (Visual Basic)Actividad no.1 (Visual Basic)
Actividad no.1 (Visual Basic)
 
Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)
Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)
Unidad 2 manipular el dibujo utilizando herramientas de diseño (1)
 
Unidad 2 Manipular el Dibujo Utilizando Herramientas de Diseño
Unidad 2 Manipular el Dibujo Utilizando Herramientas de DiseñoUnidad 2 Manipular el Dibujo Utilizando Herramientas de Diseño
Unidad 2 Manipular el Dibujo Utilizando Herramientas de Diseño
 
Unidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseñoUnidad 2 manipular el dibujo utilizando herramientas de diseño
Unidad 2 manipular el dibujo utilizando herramientas de diseño
 
Davinson clavijo castillo
Davinson clavijo castilloDavinson clavijo castillo
Davinson clavijo castillo
 

Más de Fernando Salamero

(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
(Anotaciones) Ciencia (Cuestiones) que la tiza no propone(Anotaciones) Ciencia (Cuestiones) que la tiza no propone
(Anotaciones) Ciencia (Cuestiones) que la tiza no proponeFernando Salamero
 
Ciencia (Cuestiones) que la tiza no propone
Ciencia (Cuestiones) que la tiza no proponeCiencia (Cuestiones) que la tiza no propone
Ciencia (Cuestiones) que la tiza no proponeFernando Salamero
 
(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
 
(Con anotaciones) En busca de la Física
(Con anotaciones) En busca de la Física(Con anotaciones) En busca de la Física
(Con anotaciones) En busca de la FísicaFernando Salamero
 
Timeline - En busca de la Física
Timeline - En busca de la FísicaTimeline - En busca de la Física
Timeline - En busca de la FísicaFernando Salamero
 
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
 
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
 
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 (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
 
Programación con Pygame VII
Programación con Pygame VIIProgramación con Pygame VII
Programación con Pygame VIIFernando Salamero
 

Más de Fernando Salamero (20)

(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 (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)
 
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 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
 
Programación con Pygame IX
Programación con Pygame IXProgramación con Pygame IX
Programación con Pygame IX
 

Aventura

  • 1. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO Aventura: Ficción Interactiva (Parte del código de recorte basado en un script original de Tiny Ducks On Wheels) Introducción El objetivo del programa es aprender una serie de técnicas y disponer de código que nos sirva para realizar juegos de ficción interactiva con PyGame, es decir, juegos conversacionales (del estilo de “The House”) con imágenes. Para ello, el programa se organiza en torno a tres clases y una función que podéis modificar o ampliar en vuestros propios programas: 1. La clase Narrar Un objeto de este tipo es el que se utilizar para poner en pantalla la descripción del lugar en el que se encuentra el jugador. También puede usarse para responder a sus peticiones. Cuando se crea el objeto, hay que proporcionarle una surface (sobre la que se dibujará), un rect (que marcará la zona donde ha de dibujarse), un tipo de letra y un color (que se emplearán al dibujar el texto) y el color de fondo. 2. La clase Hablar El objeto de este tipo hace las veces del cuadro donde el jugador escribe las acciones que desea realizar. Al crearse el objeto, debemos pasarle también una surface y un rect, un tipo de letra, su color y el color de fondo. PÁGINA 1 DE 10 CC: FERNANDO SALAMERO
  • 2. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO 3. La clase Juego Se trata del tipo de objeto más importante del juego, pues representa el status en el que se encuentra; localización, acciones... Como allí donde esté el jugador debe proporcionársele una descripción del entorno y, además, debe poder decir lo que quiere hacer, esta clase está ligada a las clases Narrar y Hablar. En consecuencia, cuando se crea uno de estos objetos hay que proporcionarle, una vez más, una surface (sobre lo que dibujar), una imagen (que representará el lugar en el que nos encontramos), un objeto de tipo Narrar y otro de tipo Hablar. 4. La función procesar() Esta función se encargará de procesar las órdenes del jugador para realizar las correspondientes acciones, es decir, es el parser. En un juego completo, aquí está el núcleo del desarrollo de la aventura, ya que se usará para tomar objetos, cambiar de localización, luchar, etc. Como las acciones dependerán de la situación en la que nos encontremos en el juego, cuando se invoca a la función se le ha de pasar como argumento un objeto de tipo Juego. Como quiera que el programa tiene por objetivo aprender la técnica, no es un juego realmente operativo. Sólo están implementados los comandos “norte”, “sur” y “salir” y sólo están incluidos dos lugares (y por tanto, dos imágenes). Veamos el código: PÁGINA 2 DE 10 CC: FERNANDO SALAMERO
  • 3. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO Importación de Librerías y Definición de Constantes Ya de sobras conocido; las librerías habituales, la inicialización de PyGame, la creación del objeto visor con la surface del juego y las declaraciones de los colores que vamos a usar con los textos y el diálogo. Clase JUEGO 1. En el constructor de la clase, es decir, la función __init__(), lo que hacemos es almacenar como atributos los argumentos que se le pasan para que la clase los pueda utilizar posteriormente cuando se desee. Estos atributos (a los que se accede como sabemos, con self.nombre_del_atributo) son surface, image (hemos usado image y no imagen, como nombre, por similitud a la clase pygame.sprite.Sprite), narrar y hablar. Ya hemos explicado más arriba su significado. 2. La función update() se encarga de actualizar y dibujar en pantalla la situación en la que nos encontramos en el juego (observa, de nuevo, que hemos elegido un nombre familiar...). Fíjate el orden en el que lo hacemos. Primero se dibuja la imagen de fondo (‘el paisaje’). A continuación se llama al método update() del objeto narrar para que dibuje sobre el paisaje lo que ocurre en el juego. Finalmente se llama a la función escuchar() del propio objeto para que, como veremos enseguida, se esté atento al teclado y se procesen las teclas que se vayan pulsando. 3. escuchar() se encarga de ir escribiendo en pantalla lo que se escribe hasta que se pulsa la tecla return (K_RETURN). La técnica es interesante, pues al contrario que con los programas escritos para la linea de comandos, en las surfaces de PyGame no se puede escribir directamente al estilo del conocido raw_input(). Veamos cómo se ha implementado: Lo primero es calcular cuántas letras nos caben en el cuadrado de texto que hará las veces de diálogo. Veremos en breve que el objeto hablar tiene un atributo de tipo Rect (que llamaremos rect) que indica la zona en la que se va a poner en pantalla. Así que podemos averiguar su anchura total en pixeles con hablar.rect.w . Si lo dividimos por la anchura de una letra típica, como la letra ‘a’, sabremos cuántas letras nos van a caber. Afortunadamente, el objeto de tipo hablar tendrá también un atributo de tipo Font (llamado tipoLetra) que posee (mira la documentación) una función miembro ( size() ) que nos da la anchura en pixeles de un carácter. ¡Estupendo! Almacenaremos cuántas letras nos caben en la variable maximo. Es más fácil verlo que contarlo: maximo = self.hablar.rect.w / self.hablar.tipoLetra.size('a')[0] (el [0] del final es por que, como habrás visto en la documentación, la función size() nos devuelve una tupla con la anchura y la altura, así que nos interesa el primer elemento). Probablemente, si has probado a escribir texto con PyGame habrás tenido problemas con los acentos o con los caracteres no anglosajones como ‘ñ’. Para que se muestren correctamente, necesitamos pasarle los textos con codificación unicode. No te preocupes; basta añadirle una u como prefijo a una cadena de texto para que se considere como unicode. Es por eso por lo que se ha escrito self.hablar.frase = u'' PÁGINA 3 DE 10 CC: FERNANDO SALAMERO
  • 4. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO para inicializar una cadena de texto (en blanco) a la que se añadirán las teclas que se vayan pulsando. De nuevo, frase será un atributo del objeto hablar que se encargará de memorizar las órdenes que se vayan dando en el juego. Lo siguiente es dibujar el cuadrado que enmarca la zona donde se escribirán nuestras ordenes. La función cuadrado() del objeto hablar se encargará de ello. Naturalmente, si queremos que se muestre inmediatamente en pantalla, tendremos que invocar a pygame.display.update(). Vamos a la parte final. Necesitamos un bucle que vaya capturando las teclas pulsadas y que termine cuando se pulse return. La variable booleana hablando nos ayudará en la tarea; dentro del bucle, miramos la cola de eventos de la forma habitual y si la tecla pulsada es K_RETURN, hablando se pone a False, el bucle acabará y se saldrá de la función escuchar(). Si la tecla pulsada es otra, querremos escribirla en pantalla. Afortunadamente, PyGame dispone de evento.unicode que nos da, precisamente, el texto de la tecla pulsada en codificación unicode. La función que se encargará de usar esta pulsación para escribir en pantalla será la función update() del objeto hablar: self.hablar.update(evento.unicode) Un matiz. Si la tecla pulsada es la de borrar (K_BACKSPACE), querremos que se elimine la última tecla pulsada, de allí la instrucción self.hablar.frase = self.hablar.frase[:-1] que hace precisamente eso (y no hay que pasarle ningún valor para dibujar). Además, hay que controlar que el número de teclas pulsadas no superen el máximo deseado (en caso contrario, el texto se saldría del cuadro), lo que se consigue mirando si len(self.hablar.frase) < maximo. Clase Hablar Se encarga de mostrar y almacenar las órdenes del jugador. 1. __init__(), como es habitual, guarda como atributos los valores que se pasan al objeto cuando se crea. Además, se definen dos atributos más: margen marca el tamaño del margen, ya que si el texto comienza a escribirse justo en el borde del cuadro queda poco elegante; y frase contendrá, como hemos visto, lo que escribe el jugador. 2. La función cuadrado() realza la zona en la que se va a escribir. Para que no tape la parte de la imagen de fondo que tiene detrás tendremos que aplicarle transparencia. ¿Cómo hacerlo? Primero creamos una surface del tamaño del rect del objeto que llamamos cuadrado. Indicamos que vamos a usar transparencia con el ya conocido convert_alpha(). ¿Cuánta transparencia? Eso se indica con set_alpha() ; cuanto menor sea el valor que le pasemos, tanto más transparente será. Finalmente, pintamos el cuadrado entero del color deseado con fill() y se dibuja el resultado sobre la surface que se ha pasado al objeto (típicamente, nuestro visor). 3. Al método update(), si recordamos lo que hemos visto en la clase Juego, le pasamos el valor de evento.unicode (la tecla pulsada). Ese parámetro lo hemos llamado tecla en la implementación de la función. El objetivo es añadir dicha tecla a la variable frase y dibujar el resultado. PÁGINA 4 DE 10 CC: FERNANDO SALAMERO
  • 5. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO Las primeras dos líneas posicionan dónde va a escribirse, dejando el margen pertinente. A continuación se añade a frase el valor de tecla (todo está en unicode, así que es correcto), se dibuja el marco semitransparente, se dibuja el texto y se actualiza la pantalla para que se muestre. ¡Muy bien! Clase Narrar Muestra la descripción del lugar donde se encuentra el jugador o cualquier otro mensaje que se desee como respuesta a una acción, a través de su atributo texto. La idea es hacerlo de forma similar a la clase anterior pero ahora el problema es distinto. El texto entero ya lo tenemos pero, por contra, puede ser muy largo y ocupar muchas líneas. La clase se encargará de ajustar automáticamente el texto al tamaño disponible. 1. __init__() almacena, como es habitual, los parámetros con los que se crea el objeto en atributos propios (para usarlos posteriormente). Hay un añadido, como ya hemos comentado, texto. 2. cortaTexto() es un método que toma como argumento un número que representa el tamaño máximo en pixeles que puede ocupar una línea de texto. El objetivo de la función es, partiendo del texto almacenado en texto, dividirlo en una lista de líneas que respeten el ancho dado. Con ello se consigue que sea cual sea el valor de texto, se ajuste y quepa dentro de la zona donde se va a escribir. Para realizarlo, y usando nuestra vieja amiga split(), el texto se divide en una lista de líneas de partida (para conservar los puntos y aparte que pudiera tener): lineas = self.texto.split("n") (el código especial ‘n’ es la marca de nueva línea en Linux). A continuación creamos una lista vacía, resultado, en donde se irán añadiendo las lineas con el tamaño correcto. El resto del trabajo se realiza con un bucle for que recorre todas las lineas anteriores. Para cada una de ellas, palabras contiene su lista de palabras (de nuevo usando split()). La idea es ir añadiendo palabras, calcular cuanto tamaño tiene cada una, y si no se supera el tamaño máximo ir a por la siguiente. En el momento en el que se supere dicho tope, se cambia de linea (es decir, se añade la línea a la lista y se empiezan a mirar las siguientes palabras). Intenta seguir el proceso. Ten en cuenta que se calcula el ancho en pixeles de un texto con size(), que se añaden elementos a la lista con el método append() de los objetos list, y que para concatenar textos se usa el método join() de los objetos str. En cualquier caso, la función termina devolviendo como valor de salida a resultado, la lista de líneas deseada. 3. La función update() toma como único argumento un número, margen, cuyo significado es evidente por el nombre. Comenzamos calculando la posición en la que situar el texto horizontalmente, dejando el margen y obteniendo la lista de líneas que se van a escribir, lineas, llamando al método cortaTexto() que hemos visto hace un momento. Observa que se ha tenido en cuenta también el margen para indicar el máximo tamaño disponible (se resta dos veces, contando ambos lados). Para centrar el texto verticalmente, necesitamos saber cuanto ocupan las líneas. En nuestro auxilio viene el método get_linesize() de los objetos Font. Nos devuelve la altura en pixeles que ocupa una linea de texto con ese tipo de letra. Una vez conocido, para conseguir que el texto quede en la parte central de la zona de impresión, calculamos su coordenada vertical así: PÁGINA 5 DE 10 CC: FERNANDO SALAMERO
  • 6. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO posy = self.rect.top + (self.rect.h - alturaLinea * len(lineas)) / 2 (observa que a la altura de la zona que ocupa el texto, se le resta la altura total de todas las líneas y el resultado se divide por dos para que el margen sea el mismo por arriba que por abajo; probablemente necesitarás hacerte un dibujo para entenderlo). Ya podemos pasar a dibujar. Primero, de forma similar a como hacía la función cuadrado() en la clase Hablar, dibujamos el cuadrado de fondo semitransparente. A continuación, recorremos todas las líneas del texto y las dibujamos. Fíjate que después de dibujar una línea, se añade a posy el valor de la altura de la línea calculada para que la siguiente se dibuje debajo, en el lugar correcto. Y, finalmente, se vuelca todo en pantalla para que lo visualice el jugador. función procesar() En un juego real esta función sería bastante más complicada y extensa y ésta es la razón por lo que se implementa como una función externa y no como un método más de la clase Juego. De hecho, para poder modificarlo, juego se pasa como argumento a la función. Nuestro procesar() simplemente comprueba cuál es la imagen de fondo actual (es decir, juego.image) para actuar convenientemente. Si se trata de castillo sólo haremos caso cuando la frase que ha escrito el jugador sea ‘norte’; entonces cambiamos la imagen a patio y la descripción a frase2. Algo similar ocurre cuando la imagen actual es patio; la única salida es al sur y sólo se obedece en tal caso. Por otra parte, si el jugador escribe ‘salir’ el juego debe terminar. Lo dicho, en un juego serio aquí se harían muchas comprobaciones. Además, nadie nos impide añadir más atributos a la clase Juego para que se almacene más información sobre el jugador (objetos que lleva, salud, armas, etc). Recuerda que en el juego ‘TheHouse’, el parser era bastante largo y usaba bastantes variables de estado. Cuerpo Principal del Juego Llegamos al último bloque del juego. Para empezar, cargamos las imágenes de fondo castillo y patio y definimos las descripciones de ambas localizaciones, frase1 y frase2. En un juego completo, lo ideal sería una lista o un diccionario y no variables sueltas. Continuamos definiendo los tipos de letra para la descripción de los lugares y las situaciones (letraNarrar) y para el diálogo con el ordenador (letraHablar). También se definen las zonas donde se van a mostrar con sendos Rect (dondeTexto y dondeComando). Justo antes del bucle del juego se crean los objetos que lo controlan; narrar, hablar y juego. En la creación de este último se usan los dos anteriores. Observa que para inicializar el juego necesitamos proporcionarle los datos de por donde empezar. La imagen de fondo se pasa al crearlo (castillo) y la descripción del lugar se pone a mano con narrar.texto = frase1 Finalmente, el bucle del juego realiza una y otra vez las dos tareas obvias; mostrar en pantalla la situación actualizada y esperar las acciones del usuario con juego.update() y procesar lo que haya introducido el jugador con procesar(juego). PÁGINA 6 DE 10 CC: FERNANDO SALAMERO
  • 7. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO # -*- coding: utf-8 -*- #------------------------------------------------------------------- # aventura.py # (cortaTexto basado en un script de Tiny Ducks On Wheels) #------------------------------------------------------------------- import pygame, sys from pygame.locals import * AMARILLO = (200,200,0) BLANCO = (200,200,200) VERDE = (0,100,0) LILA = (50,0,50) pygame.init() visor = pygame.display.set_mode((800,600)) #------------------------------------------------------------------- # Clase Juego # (Clase principal que coordina las demás) #------------------------------------------------------------------- class Juego: def __init__(self, surface, imagen, narrar, hablar): self.surface = surface self.image = imagen self.narrar = narrar self.hablar = hablar def update(self): self.surface.blit(self.image, (0,0)) self.narrar.update(10) self.escuchar() def escuchar(self): maximo = self.hablar.rect.w / self.hablar.tipoLetra.size('a')[0] self.hablar.frase = u'' self.hablar.cuadrado() pygame.display.update() hablando = True while hablando: for evento in pygame.event.get(): if evento.type == QUIT: pygame.quit() sys.exit() elif evento.type == KEYDOWN: PÁGINA 7 DE 10 CC: FERNANDO SALAMERO
  • 8. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO if evento.key == K_RETURN: hablando = False elif evento.key == K_BACKSPACE: self.hablar.frase = self.hablar.frase[:-1] self.hablar.update(u'') elif len(self.hablar.frase) < maximo: self.hablar.update(evento.unicode) #------------------------------------------------------------------- # Clase Hablar # ( Gestiona ka introducción de texto del usaurio) #------------------------------------------------------------------- class Hablar: def __init__(self, surface, rect, tipoLetra, colorTexto, colorFondo): self.surface = surface self.rect = rect self.tipoLetra = tipoLetra self.color = colorTexto self.colorFondo = colorFondo self.margen = 10 self.frase = u'' def cuadrado(self): cuadrado = pygame.Surface((self.rect.w,self.rect.h)) cuadrado.convert_alpha() cuadrado.set_alpha(200) cuadrado.fill(self.colorFondo) self.surface.blit(cuadrado, self.rect.topleft) def update(self, tecla): x = self.rect.left + self.margen y = self.rect.top + self.margen self.frase += tecla self.cuadrado() self.surface.blit(self.tipoLetra.render(self.frase, True, self.color), (x,y)) pygame.display.update() #------------------------------------------------------------------- # Clase Narrar # ( Muestra las descripciones de las situaciones) #------------------------------------------------------------------- class Narrar: def __init__(self, surface, rect, tipoLetra, colorTexto, colorFondo): self.surface = surface self.rect = rect self.tipoLetra = tipoLetra self.color = colorTexto PÁGINA 8 DE 10 CC: FERNANDO SALAMERO
  • 9. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO self.colorFondo = colorFondo self.texto = u'' def cortaTexto(self, anchoTotal): lineas = self.texto.split("n") resultado = [] for linea in lineas: palabras = linea.split(" ") comienzo = 0 i=0 while i < len(palabras): ancho = self.tipoLetra.size(" ".join(palabras[comienzo:i+1]))[0] if ancho > anchoTotal: resultado.append(" ".join(palabras[comienzo:i])) comienzo = i i -= 1 elif i is len(palabras) - 1: resultado.append(" ".join(palabras[comienzo:i + 1])) i += 1 return resultado def update(self, margen): posx = self.rect.left + margen lineas = self.cortaTexto(self.rect.width - 2*margen) alturaLinea = self.tipoLetra.get_linesize() posy = self.rect.top + (self.rect.h - alturaLinea * len(lineas)) / 2 cuadrado = pygame.Surface((self.rect.w, self.rect.h)) cuadrado.convert_alpha() cuadrado.set_alpha(200) cuadrado.fill(self.colorFondo) self.surface.blit(cuadrado, (self.rect.left,self.rect.top)) for linea in lineas: self.surface.blit(self.tipoLetra.render(linea, True, self.color), (posx, posy)) posy = posy + alturaLinea pygame.display.update() #------------------------------------------------------------------- # Función procesar() # ( El parser del juego) #------------------------------------------------------------------- def procesar(juego): if juego.image == castillo and juego.hablar.frase == 'norte': juego.image = patio juego.narrar.texto = frase2 elif juego.image == patio and juego.hablar.frase == 'sur': PÁGINA 9 DE 10 CC: FERNANDO SALAMERO
  • 10. PROGRAMA: AVENTURA CURSO: 1º BACHILLERATO juego.image = castillo juego.narrar.texto = frase1 elif juego.hablar.frase == 'salir': pygame.quit() sys.exit() #------------------------------------------------------------------- # Cuerpo Principal del Juego #------------------------------------------------------------------- castillo = pygame.image.load('castillo.jpg').convert() patio = pygame.image.load('patio.png').convert() frase1 = u'Abres los Ojos...nNo recuerdas nada. ¿Dónde estás? Al norte hay una puerta.' frase2 = u'Un patio se abre ante ti. Al sur está la puerta que has traspasado.' letraHablar = pygame.font.Font('Grandezza.ttf', 24) letraNarrar = pygame.font.Font('Adolphus.ttf', 24) dondeTexto = pygame.Rect((100,300,600, 200)) dondeComando = pygame.Rect((100,550,600,40)) narrar = Narrar(visor, dondeTexto, letraNarrar, AMARILLO, LILA) hablar = Hablar(visor, dondeComando, letraHablar, BLANCO, VERDE) juego = Juego(visor, castillo, narrar, hablar) narrar.texto = frase1 while True: juego.update() procesar(juego) PÁGINA 10 DE 10 CC: FERNANDO SALAMERO