Programar Juegos Arcade
con Python y Pygame

Chapter 11: Gráficos de Mapas de bits y Sonido

Si queremos ir más allá de las formas simples como círculos o rectángulos, debemos dotar a nuestros programas de la habilidad para trabajar con imágenes de mapas de bits. Este tipo de imágenes pueden ser fotografías o gráficos creados con algún programa de dibujo.

Pero solo con las imágenes no es suficiente. Los juegos necesitan también sonido! En este capítulo te enseñaremos como incluir este tipo de archivos en tus juegos.

11.1 Guardemos el Programa en una Carpeta

Video: Organizando un proyecto en una carpeta

Hasta ahora, los programas que hemos hecho, implicaban solo un archivo. Ahora que vamos a incluir imágenes y sonidos, tenemos más archivos que serán parte de nuestro programa. Es fácil mezclarlos con otros programas que estemos desarrollando. La forma de mantener todo organizado, es poner cada uno de esos programas dentro de su respectiva carpeta. Antes de comenzar cualquier nuevo proyecto, pulsa sobre 'Carpeta Nueva' y utilízala para poner en ella todos los archivos, tal como se ve en la Figura 11.1.

fig.create_a_folder
Figure 11.1: Crear una carpeta nueva

11.2 Establecer Una Imagen de Fondo

Vídeo: Organizar un proyecto dentro de una carpeta

¿Necesitas una imagen de fondo para tu juego? Encuentra una como la de la Figura 11.2. Si estás buscándola en Internet a través de tu navegador, normalmente basta con hacer clic en el botón derecho del ratón y seleccionar Guardar imagen como.... Guarda la imagen en la carpeta que te acabas de crear para nuestro juego.

fig.imagen_defondo
Figure 11.2: Imagen de Fondo

Cualquier imagen usada en el juego debe previamente haber sido dimensionada correctamente. No uses una imagen de 5000x5000 píxeles, tomada con una cámara de alta resolución, e intentes cargarla en una pantalla de 800x600. Utiliza algún programa de retoque de imágenes (hasta el MSPaint serviría) para redimensionar y/o cortar la imagen antes de usarla en tu programa Python.

Cargar una imagen es un proceso sencillo que requiere de una sola línea de código. Pero lo que contiene esa línea de código necesita de una explicación que desarrollaremos en tres partes. La primera versión de nuestro comando load, cargará un archivo llamado saturn_family1.jpg. Este archivo debe encontrarse en la misma carpeta donde se aloja nuestro programa, de otra forma el ordenador no lo encontrará.

pygame.image.load("saturn_family1.jpg")

Respeta las imágenes que posean derechos de autor (copyright). Publicar imágenes sobre las cuales no tienes derechos es una acción ilegal. Si lo que estás haciendo es un trabajo que no vas a compartir, entonces no hay problema. Si estás haciendo un trabajo de clase, consulta con tu profesora o profesor acerca de su política sobre este asunto.

Para trabajos en clase, yo sugiero añadir un comentario en el programa, justamente antes de cargar la imagen. Indica de dónde viene la imagen, tal como hicimos en el ejemplo anterior (No pongas a Google como fuente, eso es como usar “biblioteca” como tu fuente bibliográfica. Encuentra la página web original de la imagen.)

Este código cargará la imagen, pero todavía no hay forma de referenciarla y mostrarla! Necesitamos una variable que reciba lo que el comando load() devuelva. En la siguiente versión, creamos una nueva variable llamada imagen_defondo.

imagen_defondo = pygame.image.load("saturn_family1.jpg")

Por último, necesitamos que la imagen sea convertida a un formato con el que Pygame pueda trabajar fácilmente. Para ello añadimos .convert() a la función que carga la imagen. La función .convert() es un método de la clase Image. Hablaremos más sobre clases, objetos y métodos en el Capítulo 12.

Todas las imágenes deberían cargarse usando un código similar al de la siguiente línea. Basta con ajustar el nombre de la variable y el del archivo a nuestro caso.

imagen_defondo = pygame.image.load("saturn_family1.jpg").convert()

La carga de la imagen debería hacerse antes del bucle principal del programa. Aunque es posible hacerlo dentro, esto provocaría que el programa extrajera la imagen del disco veinte o más veces por segundo. Algo totalmente innecesario. Basta con hacerlo una vez al iniciarse el programa.

Para mostrar la imagen en pantalla usamos el comando blit. Éste “vuelca” la imagen en pantalla. Ya lo hemos usado previamente en el Capítulo 5 cuando quisimos mostrar texto en la pantalla de juego.

El comando blit es un método de la variable pantalla. Por ello, debemos inicializar nuestro comando por pantalla.blit. Después, tenemos que pasar la imagen a volcar, y dónde hacerlo. Este comando debe ir dentro del bucle principal, de forma que se dibuje en cada fotograma:

pantalla.blit(imagen_defondo, [0, 0])

Este código vuelca la imagen residente en imagen_defondo sobre la pantalla empezando en las coordenadas (0, 0).

11.3 Mover una Imagen

Video: Mover una Imagen

Bien, ahora queremos cargar la imagen y moverla alrededor de la pantalla. Empezaremos con un sencilla nave espacial de color naranja. Esta imagen y otras igual de buenas puedes obtenerlas de http://kenney.nl/. Ver la Figura 11.3. La imagen de la nave puede descargarse desde la página web del libro, o también puedes escoger otras imágenes en formato .gif o .png, con fondo ya sea blanco o negro. No vayas a usar imágenes con formato .jpg.

fig.imagen_protagonista
Figure 11.3: Imagen del jugador

Para cargar esta imagen necesitamos el mismo tipo de comandos que usamos con la imagen de fondo. En este caso asumimos que el archivo se ha guardado como jugador.png.

imagen_protagonista = pygame.image.load("jugador.png").convert()

En el interior del bucle principal, las coordenadas del ratón son extraídas y luego pasadas a otra función blit como las coordenadas donde se debe dibujar la imagen:

#Obtiene la posición actual del ratón, devolviéndola como
#una lista con dos números.
posicion_jugador = pygame.mouse.get_pos()
x = posicion_jugador[0]
y = posicion_jugador[1]

# Vuelca la imagen en la pantalla:
pantalla.blit(imagen_protagonista, [x, y])

Vaya, tenemos un problema. La imagen es una nave espacial con un fondo negro fijo. Así que cuando la imagen se dibuja, el programa muestra la siguiente Figura 11.4.

fig.nontrans_background

Lo que queremos es solo una nave espacial y no una nave con un fondo rectangular! Pero todas las imágenes que podemos cargar son rectangulares. Entonces ¿cómo hacemos para visualizar solo la parte de la imagen que nos interesa? La forma de conseguirlo es decirle al programa que haga “transparente” uno de los colores, de forma que desaparezca. Esto se puede hacer inmediatamente después de la carga. La siguiente línea convierte el color negro (asumiendo que NEGRO es una variable ya definida) en transparente:

imagen_protagonista.set_colorkey(NEGRO)

Esto debería funcionar con la mayoría de archivos del tipo .gif o .png. En el caso de archivos .jpg, lo más probable es que no sea así. El formato .jpg es fantástico para contener fotografías, pero la imagen es modificada ligeramente por el algoritmo usado para reducir su tamaño. Las imágenes del tipo .gif y .png también han sido comprimidas, pero el algoritmo de compresión usado en este caso no modifica la imagen original. El formato .bmp no comprime en absoluto las imágenes, con el resultado de acabar con archivos de un tamaño enorme. Debido a que el formato .jpg modifica la imagen, no todo el color de fondo será el mismo. En la Figura 11.5 se puede ver una nave espacial guardada en formato jpeg con fondo blanco. El blanco alrededor de la nave no es exactamente (255, 255, 255), pero se le aproxima bastante.

fig.jpeg_artifacts
Figure 11.5: Defectos en la Compresión JPEG

Si vas a elegir una imagen que luego sea transparente, escoge los formatos .gif o .png. Son los mejores formatos para artes gráficas. Las fotos, por contra, deberían ser .jpg. Ten en cuenta que no basta con cambiar la extensión de un archivo .jpg para convertirlo, por ejemplo en .png. Siempre será .jpg le pongas el nombre que le pongas. Hace falta usar un programa gráfico para convertir entre los distintos formatos. Pero esto no solucionará las alteraciones que haya sufrido la imagen.

Aquí tienes tres buenos sitios donde buscar imágenes gratuitas para tus programas:
Kenney.nl
OpenGameArt.Org
HasGraphics.com

11.4 Sonidos

Video: Sonidos

En esta sección reproduciremos el sonido de un láser cuando pulsemos el ratón. El sonido lo obtuvimos previamente de Kenney.nl. Puedes descargarlo también desde:
ProgramArcadeGames.com/python_examples/laser5.ogg

Al igual que sucede con las imágenes, debemos cargar los sonidos antes de su uso. Esto puede hacerse en cualquier punto antes del bucle principal. La siguiente línea carga un archivo de sonido y crea una variable llamada pulsar_sonido que lo referencia:

pulsar_sonido = pygame.mixer.Sound("laser5.ogg")

Podemos oír el sonido usando el comando siguiente:

pulsar_sonido.play()

¿Pero dónde colocamos esta línea? Si lo hacemos dentro del bucle principal, se ejecutará 20 veces por segundo. ¡Desesperante! Necesitamos una especie de “disparador”. Si ocurre cierta acción, entonces, se ejecuta el sonido. Por ejemplo, usando el siguiente código, el sonido se escuchará cuando el usuario presione el ratón:

for evento in pygame.event.get():
    if evento.type == pygame.QUIT:
        hecho = True
    elif evento.type == pygame.MOUSEBUTTONDOWN:
        pulsar_sonido.play()

Los archivos de audio no comprimidos, habitualmente terminan en la extensión .wav. Estos archivos son más grandes que los de otros formatos, debido a que no se les ha pasado ningún algoritmo que reduzca su tamaño. También tenemos el popular .mp3, pero este formato posee unas patentes que lo convierten en poco recomendable para ciertas aplicaciones. Otro formato, gratuito, es el OGG Vorbis que termina en la extensión .ogg.

Pygame no reproduce todos los archivos .wav que puedas encontrarte en Internet. Si ves que no se reproducen, puedes intentar convertirlos mediante el programa Audacity en un archivo ogg-vorbis, con extensión .ogg. Este formato ocupa poco espacio y es compatible con Pygame.

Si lo que quieres es una música de fondo para tu programa, puedes mirar el siguiente ejemplo:
ProgramArcadeGames.com/python_examples/f.php?lang=es&file=background_music.py

Por favor, recuerda que no puedes redistribuir música con copyright en tus programas. Si haces un vídeo con este tipo de música de fondo, algunos sitios como Youtube y otros similares, lo marcarán como una violación del copyright.

Puedes encontrar sonidos gratuitos para tus programas en las siguientes páginas:
OpenGameArt.Org
www.freesound.org

11.5 Listado Completo

"""
 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/

 Explanation video: http://youtu.be/4YqIKncMJNs
 Explanation video: http://youtu.be/ONAK8VZIcI4
 Explanation video: http://youtu.be/_6c4o41BIms
"""

import pygame

# Definimos algunos colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)

# Inicializamos
pygame.init()

# Creamos una pantalla de 800x600.
pantalla = pygame.display.set_mode([800, 600])

# Establecemos el nombre de la ventana.
pygame.display.set_caption('CMSC 150 es divertido')

reloj = pygame.time.Clock()

# Antes del bucle cargamos el sonido:
sonido_click = pygame.mixer.Sound("laser5.ogg")

# Establecemos la posición de los gráficos
posicion_base = [0, 0]

# Carga y sitúa los gráficos.
imagen_de_fondo = pygame.image.load("saturn_family1.jpg").convert()
imagen_personaje = pygame.image.load("playerShip1_orange.png").convert()
imagen_personaje.set_colorkey(NEGRO)

hecho = False

while not hecho:
    reloj.tick(10)
    
    for evento in pygame.event.get():
        if evento.type == pygame.QUIT:
            hecho = True
        elif evento.type == pygame.MOUSEBUTTONDOWN:
            sonido_click.play() 
            
    # Copia la imagen en pantalla:
    pantalla.blit(imagen_de_fondo, posicion_base)

    # Obtiene la posición actual del ratón. Devuelve ésta como
    # una lista de dos números.
    posicion_del_personaje = pygame.mouse.get_pos()
    x = posicion_del_personaje[0]
    y = posicion_del_personaje[1]
    
    # Copia la imagen en pantalla:
    pantalla.blit(imagen_personaje, [x, y])
    
    pygame.display.flip()
    reloj.tick(60)

pygame.quit()

11.6 Repaso

11.6.1 Test

Haz click para ir al Test.

11.6.2 Ejercicios

Haz click para ir a los Ejercicios.

11.6.3 Taller

Haz click para ir al Taller.


You are not logged in. Log in here and track your progress.