1. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
Animaciones Realistas
Guy se pone a andar
La animación es algo más que volcar una imagen en pantalla y moverla por ella. En
realidad, para que las animaciones parezcan realistas, necesitamos mucho más;
necesitamos que la propia imagen varíe a medida que la desplazamos. Para
ilustrar la forma de hacerlo, vamos a usar un personaje famoso; Guybrush
Threepwood, el protagonista de la saga de videojuegos Monkey Island (por cierto, si
no la conoces te la aconsejo, es una de las sagas más famosas y entretenidas de la historia
de los videojuegos).
Conseguiremos algunas imágenes de nuestro personaje por Internet y trabajaremos hasta
que la animación sea aceptable (no perfecta, pues las imágenes disponibles son limitadas;
en un juego real, el ilustrador que trabaja con el programador dibuja cada una de las
posiciones y los movimientos para que produzca un movimiento suave)
¡Escribamos código!
PÁGINA 1 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
2. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy01.py
El primer paso es, partiendo de una imagen de nuestro personaje, cargarla en memoria y
hacer que se desplace por la pantalla. Sería algo así:
# -*- coding: utf-8 -*-
# En este primer ejemplo, ponemos la imagen de Guy en pantalla,
# desplazándolo con las teclas 'a' y 's'.
import pygame, sys
from pygame.locals import *
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Cargar la imagen del hombre
guy = pygame.image.load('guy.jpg').convert()
# Variable que controla la posición de Guy
pos = 100
# El bucle de eventos
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Modificar posición en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
pos = pos - 1
if teclasPulsadas[K_s]:
pos = pos + 1
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar a Guy
visor.blit(guy, (pos,100))
# Volcar la surface en la ventana de pygame
pygame.display.update()
PÁGINA 2 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
3. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
Ya conocemos las técnicas necesarias para entender el código anterior. Sabemos cargar
imágenes en memoria, comprobar si se ha pulsado una determinada tecla y desplazar
objetos por la pantalla modificando sus coordenadas.
Lo único matizable es que usamos una imagen sin transparencias. Si tuviera un fondo
transparente, se nos movería por la pantalla sin problemas. Como no es el caso, para
disimularlo, hemos elegido un color de fondo para la ventana similar al de la
propia imagen (hay otros métodos, se puede indicar a PyGame que use determinado
color como color transparente, pero entonces nos hemos asegurar que el propio
fondo de la imagen es exactamente de ese color y no varía ningún pixel que se notaría con
el movimiento; éste, por desgracia, es nuestro caso).
PÁGINA 3 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
4. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy02.py
Lo anterior queda muy artificial. ¿Acaso alguien va por la calle completamente rígido y
deslizándose? Si queremos animaciones realistas, necesitamos que la imagen del
protagonista vaya cambiando a medida que va andando; pies juntos, avanza el pie derecho,
lo apoya, hace lo propio con el pie izquierdo, etc.
Hay varias maneras de hacer esto, pero todas pasan por cargar diferentes imágenes del
personaje que queremos animar y dibujarlas en los momentos apropiados. Pero antes de
ello, ¿cómo conseguimos esas imágenes y cómo disponemos de ellas?
Tanto si eres un buen dibujante como si buscas por Internet tus recursos (libres), una
forma típica de tener archivadas las diferentes imágenes es en un solo archivo de
sprite. Para que te hagas una idea, éste es el que vamos a usar:
Esta única imagen contiene todos los pasos intermedios que va a dar nuestro protagonista
(de paso puedes ver cómo era en la versión original del juego y cómo quedó en la nueva
versión). Un aviso; como este trabajo es sólo con intención pedagógica, la animación no va
a quedar del todo bien. En realidad necesitaríamos más fotogramas del movimiento o
gestionar mejor la posición de como lo vamos a hacer (fíjate que el tamaño que ocupa cada
fotograma es distinto). En cualquier caso, para aprender la técnica nos bastará.
El código que simplemente extrae uno de los fotogramas de la imagen anterior es el
siguiente:
PÁGINA 4 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
5. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
# -*- coding: utf-8 -*-
# En este segundo ejemplo, ponemos la imagen de Guy cargándola
# desde el archivo de sprites que contiene todas las imágenes.
import pygame, sys
from pygame.locals import *
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Cargar la imagen de Guy
guy = pygame.image.load('sprites.jpg').convert()
# Variable que controla la posición de Guy
pos = 100
# Posición de la parte de la imagen que se visualiza
x = 130
y = 10
w = 120
h = 340
# El bucle de eventos
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Modificar posición en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
pos = pos - 1
if teclasPulsadas[K_s]:
pos = pos + 1
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar a Guy
visor.blit(guy, (pos,100), (x,y,w,h))
# Volcar la surface en la ventana de pygame
pygame.display.update()
PÁGINA 5 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
6. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
La primera modificación, obviamente, es que al archivo de imagen que hemos de cargar en
memoria es distinto:
guy = pygame.image.load('sprites.jpg').convert()
En la variable guy, por tanto, se almacenan todos los fotogramas de la animación del
personaje. Para indicar cuál es el fotograma que queremos usar, necesitamos indicárselo
con las coordenadas de un rect de PyGame (con cualquier programa de dibujo o retoque,
como GIMP, podemos ver cuáles son).
x = 130
y = 10
w = 120
h = 340
El significado, aunque debiera ser evidente, lo tenemos en la siguiente imagen:
x y
h
w
El resto es simplemente usar la función blit para indicar que se quiere volcar en pantalla
sólo esta parte de la imagen:
visor.blit(guy, (pos,100), (x,y,w,h))
En efecto, la última tupla (x,y,w,h), como puede verse en el documento de referencia de
PyGame, indica que sólo debe dibujarse parte de una imagen.
PÁGINA 6 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
7. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy03.py
Aunque en las dos versiones anteriores el resultado es el mismo, hemos visto que el código
hace cosas muy distintas. En la primera versión se carga una imagen que se mueve por la
pantalla. En la segunda, se carga otra imagen y se mueve por la pantalla parte de esta.
El resultado de este tercer paso va a ser el mismo también, pero de camino habremos
cargado en memoria todos los fotogramas que forman la animación del personaje aunque
sólo mostremos una. Éste es el código:
# -*- coding: utf-8 -*-
# En este tercer ejemplo, cargamos todas las imágenes de Guy desde
# el archivo de sprites aunque solo mostramos una.
import pygame, sys
from pygame.locals import *
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Cargar la imagen de Guy
fotogramas = pygame.image.load('sprites.jpg').convert()
# Variable que controla la posición de Guy
pos = 100
# Almacenamos las diferentes imágenes en un diccionario
guy = {}
guy[0] = (0, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy[2] = (260, 10, 120, 340)
guy[3] = (405, 10, 140, 340)
guy[4] = (600, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
# El bucle de eventos
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
PÁGINA 7 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
8. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
# Modificar posición en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
pos = pos - 1
if teclasPulsadas[K_s]:
pos = pos + 1
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar una imagen del hombre
visor.blit(fotogramas, (pos,100), guy[1])
# Volcar la surface en la ventana de pygame
pygame.display.update()
Para empezar, hemos cambiado el nombre de la variable que contiene a la imagen de
sprites, pues ahora es simplemente una variable intermedia.
fotogramas = pygame.image.load('sprites.jpg').convert()
El nombre de guy lo reservamos para la variable que contendrá todos los fotogramas.
¿Qué tipo de variable usar? ¿Una lista? Lo más flexible es, quizá, usar un diccionario:
guy = {}
guy[0] = (0, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy[2] = (260, 10, 120, 340)
guy[3] = (405, 10, 140, 340)
guy[4] = (600, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
Las claves del diccionario son, simplemente, números enteros que indican el orden del
fotograma. Para cada una de ellas, almacenamos un rect que indica la posición del
fotograma en la imagen de sprites (lo que antes poníamos como x, y,w y h). Observa que,
de nuevo, debemos usar un programa de dibujo o retoque para mirar cuáles son las
coordenadas de cada una de esas imágenes.
Finalmente, sólo dibujamos una de ellas con
visor.blit(fotogramas, (pos,100), guy[1])
PÁGINA 8 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
9. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy04.py
Tres versiones y Guy aún no da ningún paso... Por fin ha llegado el momento de cambiar
esto. En esta versión vamos a conseguir que, al mismo tiempo que nuestro personaje
avance, su imagen vaya cambiando.
Éste es el código:
# -*- coding: utf-8 -*-
# Y en el cuarto ejemplo, mostramos una imagen de la animación
# distinta en cada paso.
import pygame, sys
from pygame.locals import *
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Cargar la imagen de Guy
fotogramas = pygame.image.load('sprites.jpg').convert()
# Variable que controla la posición de Guy
pos = 100
# Almacenamos las diferentes imágenes en un diccionario
guy = {}
guy[0] = (0, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy[2] = (260, 10, 120, 340)
guy[3] = (405, 10, 140, 340)
guy[4] = (600, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
# Variable que controla qué imagen del hombre se muestra
cual = 0
# El bucle de eventos
while True:
for event in pygame.event.get():
PÁGINA 9 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
10. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
if event.type == QUIT:
pygame.quit()
sys.exit()
# Modificar posición en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
pos = pos - 1
if teclasPulsadas[K_s]:
pos = pos + 1
cual = cual + 1
if cual > 6:
cual = 0
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar a Guy
visor.blit(fotogramas, (pos,100), guy[cual])
# Volcar la surface en la ventana de pygame
pygame.display.update()
Observa que si ejecutas este programa verás que las cosas no salen como uno desea, ya que
la imagen cambia excesivamente rápido y no da tiempo a verla. Pero para arreglar esto
tendremos que esperar a la próxima versión...
Ahora de lo que se trata es de ver cómo cambiar la imagen en cada paso.
Vamos a hacerlo, primero, en una sola dirección (pongamos que hacia la derecha). Como
es fácil de imaginar, primero necesitamos una variable que almacene cuál es la imagen que
toca dibujar en cada momento. De ello se encarga cual:
cual = 0
Recuerda que las imágenes (en realidad, la indicación de qué parte de la imagen de sprites
hay que dibujar) están almacenadas en el diccionario guy. Como cual vale inicialmente
0, la expresión guy[cual] será en realidad guy[0], es decir, el primer fotograma de la
animación del movimiento de nuestro protagonista. Sin más que cambiar el valor de la
variable cual, la expresión anterior nos daría otro fotograma.
¿Dónde hacer el cambio de imagen? Acertaste, allí donde se mire si se ha pulsado la tecla
s, cuando hay que desplazarse a la derecha y se aumenta la coordenada pos:
if teclasPulsadas[K_s]:
pos = pos + 1
cual = cual + 1
if cual > 6:
cual = 0
PÁGINA 10 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
11. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
Como puedes ver en el if anterior, si se ha pulsado la tecla s primero se aumenta la
variable pos (recuerda que allí se almacena la coordenada x del personaje) y luego
aumentamos la variable cual para indicar, cuando más adelante se llegue al momento de
dibujar, que hay que cambiar el fotograma de la animación.
Hay que tener cuidado con el número de fotograma indicado. Fíjate que tenemos 7
imágenes para simular el movimiento, indicadas con las claves 0, 1, 2, 3, 4, 5 y 6. Eso
quiere decir que, al aumentar la variable cual no nos debemos pasar de 6. De allí que se
compruebe con un if y, en tal caso, la variable cual se ponga de nuevo a 0.
Como hemos indicado antes, no todo es tan bonito como parece. Visto en movimiento,
¡Guy parece mover los pies a toda velocidad como alma que lleva el diablo! Hmmm...
PÁGINA 11 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
12. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy05.py
El problema que tenemos en la versión anterior de nuestra animación es que no
controlamos la velocidad de ésta, con lo que en cada fotograma se cambia el dibujo de
nuestro personaje; si el programa se ejecuta a 60 fotogramas por segundo, por ejemplo,
Guy cambia de aspecto 60 veces cada segundo y de ahí la locura del movimiento de sus
piernas...
La manera de solucionarlo será ésta:
# -*- coding: utf-8 -*-
# Quinto ejemplo, controlamos la velocidad de la animación.
import pygame, sys
from pygame.locals import *
import time
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Cargar la imagen de Guy
fotogramas = pygame.image.load('sprites.jpg').convert()
# Variable que controla la posición de Guy
pos = 0
# Almacenamos las diferentes imágenes en un diccionario
guy = {}
guy[0] = (0, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy[2] = (260, 10, 130, 340)
guy[3] = (405, 10, 170, 340)
guy[4] = (600, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
# Variable que controla qué imagen de Guy se muestra
cual = 0
# Controlando el tiempo
cuanto = 100
tiempo = 0
PÁGINA 12 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
13. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
# El bucle de eventos
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Modificar posición en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
pos = pos - 1
if teclasPulsadas[K_s]:
pos = pos + 1
if pygame.time.get_ticks()-tiempo > cuanto:
tiempo = pygame.time.get_ticks()
cual = cual + 1
if cual > 6:
cual = 1
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar al hombre
visor.blit(fotogramas, (pos,100), guy[cual])
# Volcar la surface en la ventana de pygame
pygame.display.update()
La forma de controlar la velocidad a la que se cambia el aspecto del personaje es muy
parecida a la que ya vimos cuando regulamos la velocidad en el juego del Pong. Para
empezar, necesitamos dos variables que nos gestionen el tiempo de ejecución y el tiempo
que hay que esperar:
cuanto = 100
tiempo = 0
cuanto indica el número de milisegundos que hay que esperar para cambiar el dibujo.
Los valores concretos que pongamos en esta variable y en otras similares dependerán de
nosotros, de la velocidad que queramos y del número de dibujos que tengamos. La variable
tiempo, recuerda, se encarga de almacenar el momento en el que se cambia el aspecto del
fotograma, para poder comparar con este momento y ver si ha pasado el tiempo suficiente.
Por supuesto, no olvides importar la librería que gestiona el tiempo
import time
ya que allí es donde reside la función pygame.time.get_ticks() que usamos para ver el
tiempo que ha pasado:
PÁGINA 13 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
14. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
if pygame.time.get_ticks()-tiempo > cuanto:
tiempo = pygame.time.get_ticks()
cual = cual + 1
if cual > 6:
cual = 1
¿Ves que es casi lo mismo que en el Pong? Aquí se mira si ha pasado el tiempo suficiente,
en cuyo caso se cambia el fotograma. Y en caso contrario no se hace nada pues no se
ejecuta ninguna de las instrucciones del bloque if.
Otro matiz; habrás notado, quizá que hemos cambiado el número de fotograma en el que
se vuelve a empezar la animación. Antes era cual = 0 y ahora cual = 1. ¿Adivinas por
qué? En efecto, el fotograma número 0 es el que muestra a Guy parado y queda la
animación muy rara al pasar el dibujo por allí cuando está en proceso de andar. Pruébalo:
cambia el 1 por un 0 y ejecuta el programa. ¿Ves a lo que nos referimos? Claramente, el
primer fotograma de la animación andadora ha de ser el 1.
PÁGINA 14 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
15. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy06.py
Hay un defecto evidente en la versión anterior de nuestro programa, y es que cuando
dejamos de pulsar la tecla s el movimiento se para allí donde estuviera, incluido a mitad
de paso.... Lo deseable es que al dejar de moverse, Guy quede esperando quieto, no en esa
postura artificial. Otro ajuste que podemos hacer es con los dos fotogramas que abren el
paso, pues las imágenes son más anchas que las demás (no es lo mismo estar con las
piernas juntas que con las piernas abiertas).
Veamos:
# -*- coding: utf-8 -*-
# Sexto ejemplo, ajustamos la animación para que tenga
# un aspecto más realista.
import pygame, sys
from pygame.locals import *
import time
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Cargar la imagen del hombre
fotogramas = pygame.image.load('sprites.jpg').convert()
# Variable que controla la posición de Guy
pos = 0
# Almacenamos las diferentes imágenes en un diccionario
guy = {}
guy[0] = (0, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy[2] = (260, 10, 130, 340)
guy[3] = (405, 10, 170, 340)
guy[4] = (600, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
# Variable que controla qué imagen de Guy se muestra
cual = 0
# Controlando el tiempo
cuanto = 100
PÁGINA 15 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
16. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
tiempo = 0
# El bucle de eventos
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Modificar posición en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
pos = pos - 1
elif teclasPulsadas[K_s]:
pos = pos + 1
if pygame.time.get_ticks()-tiempo > cuanto:
tiempo = pygame.time.get_ticks()
cual = cual + 1
if cual == 3 or cual == 6:
pos = pos + 5
if cual > 6:
cual = 1
else:
cual = 0
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar a Guy
visor.blit(fotogramas, (pos,100), guy[cual])
# Volcar la surface en la ventana de pygame
pygame.display.update()
Lo primero es implementar la imagen de Guy parado. Ésa es precisamente la imagen 0 de
nuestro diccionario. Así que cuando no se pulse ninguna tecla, tenemos que indicar que sea
ésta y no otra la imagen que se dibuje cuando toque. Para ello, lo más sencillo es modificar
los if que miran que tecla se ha pulsado en uno solo:
if teclasPulsadas[K_a]:
...
elif teclasPulsadas[K_s]:
...
else:
cual = 0
PÁGINA 16 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
17. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
Con una estructura de esta forma, se mira si se ha pulsado la tecla a, en caso contrario se
mira si se ha pulsado la tecla s y si no se ha pulsado ninguna de las dos es cuando se
pone la variable cual a 0 para indicar que se dibujará la imagen de Guy quieto.
Lo siguiente es ajustar el desplazamiento con imágenes de diferentes tamaños. Vamos a
hacerlo de manera sencilla, simplemente dando más desplazamiento en la posición cuando
toca una de los fotogramas más anchos:
if cual == 3 or cual == 6:
pos = pos + 5
Como habrás notado, los fotogramas que en la imagen del sprite aparecen con las piernas
abiertas son la 3 y la 6 (recuerda que la primera es la 0). La cantidad que añadamos a la
variable pos dependerá del tamaño de la imagen y de cómo nos quede la animación al
probarla.
PÁGINA 17 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
18. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy07.py
Llegamos al último paso. ¿Qué nos queda? El movimiento hacia la derecha está
conseguido. Pero si pulsamos la tecla a para mover a Guy hacia la izquierda, veremos que
éste se desliza. ¡Claro! No hemos implementado el movimiento en esa dirección. Además lo
ideal sería tener otro sprite con los fotogramas del movimiento en la otra dirección, pero
este no es nuestro caso... ¿Qué podemos hacer?
El código fuente de nuestra versión definitiva será el siguiente:
# -*- coding: utf-8 -*-
# Séptimo y último ejemplo. Implementamos la animación
# en sentido contrario.
import pygame, sys
from pygame.locals import *
import time
# Inicializar pygame
pygame.init()
# Crear la surface
visor = pygame.display.set_mode((600, 600), 0, 32)
# Poner el título de la ventana
pygame.display.set_caption('Guy')
# Variable que controla la posición de Guy
pos = 0
# Cargar la imagen de Guy y su reflejo
fotogramas = pygame.image.load('sprites.jpg').convert()
fotogramas2 = pygame.transform.flip(fotogramas,True, False)
# Almacenamos las diferentes imágenes en un diccionario
guy = {}
guy2 = {}
guy[0] = (0, 10, 120, 340)
guy2[0]= (941, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy2[1]= (811, 10, 120, 340)
guy[2] = (260, 10, 130, 340)
guy2[2]= (671, 10, 130, 340)
guy[3] = (405, 10, 170, 340)
guy2[3]= (486, 10, 170, 340)
guy[4] = (600, 10, 120, 340)
guy2[4]= (341, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
PÁGINA 18 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
19. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy2[5]= (201, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
guy2[6]= (21, 10, 170, 340)
# Controlando la dirección
izquierda = True
# Variable que controla qué imagen de Guy se muestra
cual = 0
# Controlando el tiempo
cuanto = 100
tiempo = 0
# Función que actualiza el fotograma
def actualizar():
global cual, pos, tiempo
if izquierda:
pos = pos + 1
else:
pos = pos - 1
if pygame.time.get_ticks()-tiempo > cuanto:
tiempo = pygame.time.get_ticks()
cual = cual + 1
if izquierda:
if cual == 3 or cual == 6:
pos = pos + 5
if cual > 6:
cual = 1
else:
if cual == 3 or cual == 6:
pos = pos - 5
if cual > 6:
cual = 1
# El bucle de eventos
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Modificar dirección en función de la tecla pulsada
teclasPulsadas = pygame.key.get_pressed()
if teclasPulsadas[K_a]:
izquierda = False
actualizar()
elif teclasPulsadas[K_s]:
izquierda = True
actualizar()
PÁGINA 19 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
20. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
else:
cual = 0
# Dibujar el fondo de color
visor.fill((233,233,233))
# Dibujar a Guy
if izquierda:
visor.blit(fotogramas, (pos,100), guy[cual])
else:
visor.blit(fotogramas2, (pos,100), guy2[cual])
# Volcar la surface en la ventana de pygame
pygame.display.update()
En primer lugar necesitamos la imagen de los fotogramas del movimiento inverso al que
hemos tratado. Es cierto, no la tenemos, pero PyGame es estupendo y dispone de una
función que hace el trabajo por nosotros:
fotogramas2 = pygame.transform.flip(fotogramas,True, False)
La función pygame.transform.flip() toma como primer argumento una imagen y nos
devuelve una nueva imagen invertida respecto a la anterior. La forma de invertirla depende
de los dos argumentos siguientes. Si el primero de ellos es True intercambia izquierda y
derecha (es decir, una reflexión respecto al eje vertical); si el segundo es True, hace
lo propio con arriba y abajo (reflexión con respecto al eje horizontal). En nuestro
caso sólo queremos lo primero y de ahí que pasemos True y False. (Podíamos haber
cogido un programa de dibujo o de retoque y haber invertido la imagen, es cierto, pero al
hacerlo así hemos aprendido una nueva técnica que a veces es útil).
Lo siguiente es almacenar también las imágenes del nuevo sprite. Un nuevo diccionario
viene a realizar la tarea:
guy = {}
guy2 = {}
guy[0] = (0, 10, 120, 340)
guy2[0]= (941, 10, 120, 340)
guy[1] = (130, 10, 120, 340)
guy2[1]= (811, 10, 120, 340)
guy[2] = (260, 10, 130, 340)
guy2[2]= (671, 10, 130, 340)
guy[3] = (405, 10, 170, 340)
guy2[3]= (486, 10, 170, 340)
guy[4] = (600, 10, 120, 340)
guy2[4]= (341, 10, 120, 340)
guy[5] = (730, 10, 130, 340)
guy2[5]= (201, 10, 130, 340)
guy[6] = (870, 10, 170, 340)
guy2[6]= (21, 10, 170, 340)
PÁGINA 20 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
21. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
guy contiene los fotogramas del movimiento hacia la derecha y guy2 los de la izquierda.
Los valores concretos que hay que poner, como antes, o los miramos con un programa de
dibujo/retoque o hacemos algo de algebra teniendo encuenta el tamaño de la imagen y que
los segundos son un reflejo de los primeros.
Necesitamos también saber cual de los dos movimientos hay que dibujar, es decir, saber
hacia dónde nos estamos moviendo:
izquierda = True
La variable booleana izquierda indica, si es True (como ocurre al principio de la
ejecución del programa), que el movimiento es hacia la izquierda y si es False hacia la
derecha. Esto es importante, pues sólo tendremos que modificar el valor de esta variable
en el lugar apropiado de nuestro código para indicar qué imagen dibujar, siempre que
modifiquemos la parte en la que dibujamos a nuestro protagonista a esto:
if izquierda:
visor.blit(fotogramas, (pos,100), guy[cual])
else:
visor.blit(fotogramas2, (pos,100), guy2[cual])
¿Entiendes la idea? Con un bloque if miramos el valor de la variable izquierda; cuando sea
True dibujará un fotograma de guy y cuando sea False de guy2.
Pasemos a seleccionar exactamente de qué fotograma se trata. Fíjate que hay que hacer
prácticamente lo mismo en las dos direcciones, así que ¿por qué no definir una función
que lo haga y así no repetimos el código? Llamemos a esa función actualizar(), ya que
actualiza el dibujo de nuestro personaje. La parte que indica que hemos pulsado una tecla y
hay que cambiar el dibujo quedará ahora así:
if teclasPulsadas[K_a]:
izquierda = False
actualizar()
elif teclasPulsadas[K_s]:
izquierda = True
actualizar()
else:
cual = 0
Observa que si no se ha pulsado ninguna tecla, cual se pone a 0 y, más adelante, gracias a
nuestra modificación anterior, el programa dibujará el fotograma de parado correcta (hay
dos distintas, una con Guy parado mirando hacia la derecha y otra mirando hacia la
izquierda).
Respecto al movimiento, si se ha pulsado la tecla a sabemos que hay que mover a Guy
hacia la derecha, así que izquierda se pone a False y se llama a nuestra función
actualizar() para que cambie el dibujo. Si se ha pulsado la tecla s, por su parte, el
movimiento es hacia la izquierda, el valor correcto de la variable izquierda es ahora True
y se llama de nuevo a nuestra función.
Es el momento de abordar la implementación de la función actualizar(). Su código será
el siguiente:
PÁGINA 21 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
22. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
def actualizar():
global cual, pos, tiempo
if izquierda:
pos = pos + 1
else:
pos = pos - 1
if pygame.time.get_ticks()-tiempo > cuanto:
tiempo = pygame.time.get_ticks()
cual = cual + 1
if izquierda:
if cual == 3 or cual == 6:
pos = pos + 5
if cual > 6:
cual = 1
else:
if cual == 3 or cual == 6:
pos = pos - 5
if cual > 6:
cual = 1
Un matiz no muy elegante y que cambiará por completo cuando veamos como trabaja de
forma nativa PyGame con los sprites y la orientación a objetos, es la gestión de las
variables externas a la función. Una función puede usar sus propias variables,
definidas en su interior y también usar el valor de las variables que se han definido fuera
de ella. Hasta aquí todo correcto. Pero en cuanto queremos cambiar el valor de una de
estas últimas variables externas obtendremos un grosero error; Python protege las
externas y piensa que son internas y, como no están definidas, la cosa no funciona. Para
solucionarlo, existe la instrucción global. Las variables que pongamos a continuación de
dicha instrucción se declaran como externas y Python nos permite modificarlas dentro
del cuerpo de la función. En nuestro caso, vamos a modificar las variables cual, pos y
tiempo.
Lo siguiente que hay que hacer dentro de la función es modificar la posición de Guy. Aquí
no hace falta que miremos si se ha pulsado el teclado, puesto que ya se ha hecho y se ha
puesto la información en la variable izquierda. Basta poner, como vemos más arriba
if izquierda:
pos = pos + 1
else:
pos = pos - 1
(¿Ves como modificamos la variable externa pos? De ahí el global al comienzo de la
función).
El resto también es similar a la versión anterior del programa, con las modificaciones
correspondientes a las dos direcciones posibles. Simplemente miramos el valor de la
variable izquierda y actuamos en consecuencia sumando o restando y cambiando el valor
de la variable cual. Por supuesto, el código puede mejorarse, es algo redundante, pero
para nuestros efectos, es suficiente:
PÁGINA 22 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES
23. ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME
CURSO: 1º BACHILLERATO
if pygame.time.get_ticks()-tiempo > cuanto:
tiempo = pygame.time.get_ticks()
cual = cual + 1
if izquierda:
if cual == 3 or cual == 6:
pos = pos + 5
if cual > 6:
cual = 1
else:
if cual == 3 or cual == 6:
pos = pos - 5
if cual > 6:
cual = 1
Con todos estos cambios, la animación funciona aceptablemente en las dos direcciones,
como podemos comprobar si ejecutamos el programa.
PÁGINA 23 DE 23
DURACIÓN: PERÍODOS DE DOS CLASES