Programación con Pygame III

23
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! ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO PÁGINA 1 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

description

Los archivos pueden encontrarse en http://sites.google.com/site/laislalibre/informatica/python/pygame

Transcript of Programación con Pygame III

Page 1: Programación con Pygame III

Animaciones RealistasGuy 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!

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 1 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 2: Programación con Pygame III

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í:

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 2 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

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

# En este primer ejemplo, ponemos la imagen de Guy en pantalla,# desplazándolo con las teclas 'a' y 's'.

import pygame, sysfrom pygame.locals import *

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Cargar la imagen del hombreguy = pygame.image.load('guy.jpg').convert()

# Variable que controla la posición de Guypos = 100

# El bucle de eventoswhile 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()

Page 3: Programación con Pygame III

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

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 3 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 4: Programación con Pygame III

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:

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 4 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 5: Programación con Pygame III

# -*- 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, sysfrom pygame.locals import *

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Cargar la imagen de Guyguy = pygame.image.load('sprites.jpg').convert()

# Variable que controla la posición de Guypos = 100

# Posición de la parte de la imagen que se visualizax = 130y = 10w = 120h = 340

# El bucle de eventoswhile 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()

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 5 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 6: Programación con Pygame III

La primera modificación, obviamente, es que al archivo de imagen que hemos de cargar en memoria es distinto:

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

El significado, aunque debiera ser evidente, lo tenemos en la siguiente imagen:

El resto es simplemente usar la función blit para indicar que se quiere volcar en pantalla sólo esta parte de la imagen:

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.

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 6 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

guy = pygame.image.load('sprites.jpg').convert()

x = 130y = 10w = 120h = 340

x y

w

h

visor.blit(guy, (pos,100), (x,y,w,h))

Page 7: Programación con Pygame III

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, sysfrom pygame.locals import *

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Cargar la imagen de Guyfotogramas = pygame.image.load('sprites.jpg').convert()

# Variable que controla la posición de Guypos = 100

# Almacenamos las diferentes imágenes en un diccionarioguy = {}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 eventoswhile True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit()

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 7 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 8: Programación con Pygame III

Para empezar, hemos cambiado el nombre de la variable que contiene a la imagen de sprites, pues ahora es simplemente una variable intermedia.

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:

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

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

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 8 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

fotogramas = pygame.image.load('sprites.jpg').convert()

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)

visor.blit(fotogramas, (pos,100), guy[1])

Page 9: Programación con Pygame III

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, sysfrom pygame.locals import *

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Cargar la imagen de Guyfotogramas = pygame.image.load('sprites.jpg').convert()

# Variable que controla la posición de Guypos = 100

# Almacenamos las diferentes imágenes en un diccionarioguy = {}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 muestracual = 0

# El bucle de eventoswhile True: for event in pygame.event.get():

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 9 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 10: Programación con Pygame III

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:

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

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 10 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

cual = 0

if teclasPulsadas[K_s]: pos = pos + 1 cual = cual + 1 if cual > 6: cual = 0

Page 11: Programación con Pygame III

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

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 11 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 12: Programación con Pygame III

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, sysfrom pygame.locals import *import time

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Cargar la imagen de Guyfotogramas = pygame.image.load('sprites.jpg').convert()

# Variable que controla la posición de Guypos = 0

# Almacenamos las diferentes imágenes en un diccionarioguy = {}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 muestracual = 0

# Controlando el tiempocuanto = 100tiempo = 0

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 12 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 13: Programación con Pygame III

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

ya que allí es donde reside la función pygame.time.get_ticks() que usamos para ver el tiempo que ha pasado:

# El bucle de eventoswhile 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()

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 13 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

cuanto = 100tiempo = 0

import time

Page 14: Programación con Pygame III

¿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.

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 14 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

if pygame.time.get_ticks()-tiempo > cuanto: tiempo = pygame.time.get_ticks() cual = cual + 1 if cual > 6: cual = 1

Page 15: Programación con Pygame III

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, sysfrom pygame.locals import *import time

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Cargar la imagen del hombrefotogramas = pygame.image.load('sprites.jpg').convert()

# Variable que controla la posición de Guypos = 0

# Almacenamos las diferentes imágenes en un diccionarioguy = {}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 muestracual = 0

# Controlando el tiempocuanto = 100

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 15 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 16: Programación con Pygame III

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:

tiempo = 0

# El bucle de eventoswhile 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()

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 16 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

if teclasPulsadas[K_a]: ... elif teclasPulsadas[K_s]: ... else: cual = 0

Page 17: Programación con Pygame III

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:

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.

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 17 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

if cual == 3 or cual == 6: pos = pos + 5

Page 18: Programación con Pygame III

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, sysfrom pygame.locals import *import time

# Inicializar pygamepygame.init()

# Crear la surfacevisor = pygame.display.set_mode((600, 600), 0, 32)

# Poner el título de la ventanapygame.display.set_caption('Guy')

# Variable que controla la posición de Guypos = 0

# Cargar la imagen de Guy y su reflejofotogramas = pygame.image.load('sprites.jpg').convert()fotogramas2 = pygame.transform.flip(fotogramas,True, False)

# Almacenamos las diferentes imágenes en un diccionarioguy = {}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)

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 18 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 19: Programación con Pygame III

guy2[5]= (201, 10, 130, 340)guy[6] = (870, 10, 170, 340)guy2[6]= (21, 10, 170, 340)

# Controlando la direcciónizquierda = True

# Variable que controla qué imagen de Guy se muestracual = 0

# Controlando el tiempocuanto = 100tiempo = 0

# Función que actualiza el fotogramadef 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 eventoswhile 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()

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 19 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

Page 20: Programación con Pygame III

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:

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:

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

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 20 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

fotogramas2 = pygame.transform.flip(fotogramas,True, False)

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)

Page 21: Programación con Pygame III

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:

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:

¿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í:

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:

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 21 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

izquierda = True

if izquierda: visor.blit(fotogramas, (pos,100), guy[cual]) else: visor.blit(fotogramas2, (pos,100), guy2[cual])

if teclasPulsadas[K_a]: izquierda = False actualizar() elif teclasPulsadas[K_s]: izquierda = True actualizar() else: cual = 0

Page 22: Programación con Pygame III

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

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

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 22 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

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

if izquierda: pos = pos + 1 else: pos = pos - 1

Page 23: Programación con Pygame III

Con todos estos cambios, la animación funciona aceptablemente en las dos direcciones, como podemos comprobar si ejecutamos el programa.

ASUNTO: PROGRAMACIÓN CON PYTHON Y PYGAME CURSO: 1º BACHILLERATO

PÁGINA 23 DE 23 DURACIÓN: PERÍODOS DE DOS CLASES

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