Pygame
Pygame
PYGAME EN PYTHON
¿CÓMO CREAR JUEGOS?
P á g i n a 1 | 145
1.- Instalando pygame
Utilizando una interface gráfica, una ventana con la que poder interactuar con el juego.
Hasta ahora los juegos que hemos hecho han sido en modo texto usando la consola del sistema
o la consola del IDLE.
Vamos a ver como podemos hacer juegos que tengan gráficos, imágenes, que podemos utilizar
el ratón, que podamos utilizar todas las teclas del teclado en definitiva un juego tal y como lo
entendemos hoy con componentes gráficos.
Para ello necesitaremos de una librería de Python que nos permita acceder y manejar los
recursos del hardware del ordenador: Tarjeta gráfica, tarjeta de sonido, ratón, etc.
De esta forma podremos crear una ventana donde aparezcan los gráficos, las imágenes, los
sonidos y desde la cual tengamos control sobre los eventos del juego.
La única que viene instalada por defecto es Tkinter, las demás no vienen por defecto en la
instalación de Python y que hay que instalar.
La instalación de estos paquetes va a ser muy sencilla, a partir de la versión de Python 3.4 viene
por defecto un sistema para la gestión de paquetes Pip que hace muy sencilla la instalación de
cualquier paquete.
Esta aplicación se conecta a Python Package index (PyPI), que es un repositorio donde están
guardadas la mayor parte de paquetes y aplicaciones e terceros como dice la Wikipedia del
lenguaje de programación Python.
P á g i n a 2 | 145
Lo primero que vamos a comprobar si tenemos definidas las variables del entorno del sistema
para Python.
P á g i n a 3 | 145
Vamos a ver si tenemos definidas las variables para el entorno pip.
Si escribimos pip list nos mostrará los paquetes que tenemos instalados.
P á g i n a 4 | 145
Para instalar vamos a escribir pip install pygame.
Ya lo ha instalado.
Ya lo tenemos.
P á g i n a 5 | 145
Vamos al intérprete de Python y escribimos import pygame.
P á g i n a 6 | 145
2.- Primera ventana en pygame
Antes de empezar vamos a ver algunos recursos para los que les interese ir más deprisa.
https://www.pygame.org/docs/
http://programarcadegames.com/
P á g i n a 7 | 145
https://inventwithpython.com/es/
Vamos a empezar, una vez hallamos creado una carpeta creamos el archivo ejemplo1.py
Podemos ver todo los elementos que contiene y los módulos que a su vez contiene esta librería.
Vamos a hacer nuestro primer programa que consiste en abrir una ventana.
P á g i n a 8 | 145
De esta manera se inicializa
los módulos.
Para cambiar el color de la pantalla, pero para que tenga efecto hay que actualizar, tal como se
muestra en la línea 9.
P á g i n a 9 | 145
3.- Eventos de pygame
En el capítulo anterior ya vimos como creamos una primera ventana, vamos a ir recordando lo
del capítulo anterior introduciendo algunas optimizaciones para que nuestro código sea más
legible.
Creamos la ventana y a la función set_mode le tenemos que dar las dimensiones en este caso
800 x 600.
Es recomendable definir dos variables que las pondremos en mayúsculas para tratarlas como
constantes para guardar el ANCHO y ALTO.
Con la función fill la rellenamos de un color, le pasamos el valor con una tupla, pero estos valores
los vamos a almacenar en contantes.
Si dejamos así el programa la ventana se cerrará inmediatamente, casi no vamos a poderla ver.
P á g i n a 10 | 145
Mediante es bucle controlaremos cuando queremos que se cierre la ventana.
Vamos a ejecutar:
Código completo:
import pygame
pygame.init()
ANCHO = 800
ALTO = 600
BLANCO = (255,255,255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
jugando = True
while jugando:
ventana.fill(ROJO)
pygame.display.update()
pygame.quit()
P á g i n a 11 | 145
solo hemos creado la ventana pero no podemos ralizar ninguna acción sobre
ella, porque no lo hemos codificado.
Vamos a ejecutar:
Se nos muestra los eventos que recoge la ventana, en este caso como movemos el ratón por la
ventana.
Puede recoger cualquier botón que presionemos del ratón o cualquier tecla del teclado.
P á g i n a 12 | 145
En la línea 16 mientras será True no saldremos del bucle.
En la línea 17 en la variable evento recogemos un evento, este puede ser mover el ratón, pulsar
el botón del ratón o utilizar alguna tecla del ratón.
En la línea 19 si es así la varible pasa a valer False, como es la variable que compara el bucle
while, el bucle finaliza.
P á g i n a 13 | 145
Te propongo que practiques con los eventos o por mediación de una tecla.
P á g i n a 14 | 145
4.- Pantalla completa en pygame
Este es el código que hemos visto hasta ahora:
P á g i n a 15 | 145
En los eventos solamente hemos definido “Cerrara la ventana” con la x, y también como salir
del bucle presionando una tecla, en este caso la tecla ‘q’, que hemos cambiado por la tecla
Escape.
Esto nos puede ser muy útil si queremos configurar nuestros juegos a pantalla completa.
Si en cambiar el tamaño del texto, es superior al 100% sería conveniente coger una resolución
menor que en nuestro caso no lo es.
Para que nuestro juego pueda valer para otros ordenadores vamos a poner 1280 x 720.
Vamos a ejecutar.
La ventana ocupa toda la pantalla y para salir vamos a presionar la tecla Escape.
P á g i n a 16 | 145
5.- Coordenadas de pygame
Seguimos viendo las opciones que nos ofrece la librería pygame.
Hasta ahora hemos creado una ventana y simplemente lo que hemos hecho ha sido rellenarla
de un color, vamos a ver como podemos dibujar figuras dentro de la ventana.
Es este caso vamos a dibujar un cuadrado, esta función rect vale para cuadrados como
rectángulos.
P á g i n a 17 | 145
(100, 100)
P á g i n a 18 | 145
El proceso es el siguiente:
En la línea 30 le decimos que el fondo será de color negro, pero aun no se visualizará, se
guardará en memoria.
En la línea 31 dibujamos un rectángulo, con los siguientes parámetros, lugar donde se dibuja
(ventana), color podemos poner una tupla con los colores RGB o bien una constante con dichos
valores, en nuestro caso seleccionamos VERDE, y por último las coordenadas que hemos
detallado las imágenes anteriores.
Hasta que no lleguemos a la línea 34 con toda la información en memoria se mostrará la ventana
con su cuadrado.
Por otra parte es importante poner primero el fondo de la ventana, en este caso el rellenado
con el color porque si ponemos primero el cuadrado y a continuación el fondo, el fondo taparía
al cuadrado y se vería todo negro en este caso.
P á g i n a 19 | 145
6.- Dibujando con pygame
La solución:
(10,10)
(100,100)
En definitiva los parámetros son los dos primeros valores son las coordenadas x e y el tercer
valor es el acho y el curto valor el alto.
Las coordenadas del circulo no funcionan igual que la del rectángulo, ya que en el circulo su
coordenada se refiere al centro del mismo, si hacemos un radio mayor solo nos mostrará la
parte inferior derecha.
P á g i n a 20 | 145
Si queremos que el circulo deje un espacio por arriba y a la izquierda de 10 pixeles tendremos
que sumar a la coordenada la separación de la esquina que es 10 más el radio que es 50.
P á g i n a 21 | 145
El polygon cerrará el polígono, como indica la flecha.
Te propongo que practiques con las funciones rect, circle, line y polygon.
P á g i n a 22 | 145
7.- Movimiento en pygame
En este vídeo vamos a empezar a ver el movimiento. El movimiento va a ser algo importante
en muchos juegos. Movimiento de figuras o imágenes para intentar conseguir un objetivo.
Vamos a partir en una versión de programa que hemos realizado en capítulos anteriores en la
que solo tendremos un fondo negro y un cuadrado.
P á g i n a 23 | 145
Si le damos a ejecutar:
P á g i n a 24 | 145
En las línea 21 y 22 definimos dos variables para las coordenadas x e y.
En la línea 35 hacemos que la coordenada pos_x en cada ciclo incremente en 1.
En la línea 39 hemos cambiado los valores por las variables, ya que la variable pos_x se irá
incrementando.
Este será el resultado:
P á g i n a 25 | 145
Observamos como el cuadro se desplaza de izquierda a derecha hasta salir de la ventana.
En la línea 43 hacemos una demora de 5 milisegundos para que el desplazamiento no sea tan
rápido.
Ahora queremos controlar que cuando el cuadro sale por la derecha que vuelva a empezar
entrando por la izquierda.
P á g i n a 26 | 145
Te propongo que realices este proyecto:
P á g i n a 27 | 145
P á g i n a 28 | 145
P á g i n a 29 | 145
8.- Más movimiento de figuras
Este es el codigo con pequeñas rectificaciones.
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255,255,255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
# Datos
pos_x = 800
pos_y = 100
pos1_x = 200
pos1_y = 200
# Bucle principal
jugando = True
while jugando:
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
# Lógica
pos_x -= 1
pos1_x += 1
P á g i n a 30 | 145
pos1_y += 1
if pos1_y > 600:
pos1_y = -50
if pos1_x > ANCHO:
pos1_x = -50
if pos_x > ANCHO:
pos_x = -50
# Dibujos
ventana.fill(NEGRO)
pygame.draw.rect(ventana, VERDE, (pos_x,pos_y, 50,
50))
pygame.draw.rect(ventana, AZUL, (pos1_x,pos1_y, 50,
50))
# Actualizar
pygame.display.update()
pygame.time.delay(5)
# Salir
pygame.quit()
P á g i n a 31 | 145
9.- Poniendo texto en pygame
Vamos a escribir el siguiente código:
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 800
ALTO = 600
Creamos un objeto de tipo
# Colores font.SysFont con una fuente de
BLANCO = (255, 255, 255) nuestro sistema “segoe print” y un
tamaño de 30.
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
# Datos
r_x = 100
A esta función le pasamos el texto,
r_y = 300 pondremos True si queremos que
se aplique un suavizado de borde y
# Bucle principal a continuación el color por
jugador = True ejemplo BLANCO.
while jugador:
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugador = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugador = False
# Lógica
r_x += 1
P á g i n a 32 | 145
if r_x > ANCHO:
r_x = -100
# Dibujos
ventana.fill(NEGRO)
pygame.draw.rect(ventana, VERDE, (r_x, r_y, 100,
100))
ventana.blit(texto, (10, 10))
# Actualizar
pygame.display.update() Mediante al función blit pegamos el
pygame.time.delay(5) texto a la ventana con las corres-
pondientes coordenadas.
# Salir
pygame.quit()
Vamos a cambiar:
P á g i n a 33 | 145
Cambiamos de nuevo a True.
Para colocar un texto tenemos que realizar 3 pasos, primero definir una fuente, segundo crear
un objeto de tipo superficie donde escribir el texto y asignarle color y tercero insertar esta
superficie en la ventana.
Cambiamos la fuente.
P á g i n a 34 | 145
10.- Añadiendo puntuación
Vamos a seguir con el código del capítulo anterior:
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0) Definimos otro tipo
VERDE = (0, 255, 0) de fuente.
AZUL = (0, 0, 255)
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
# Datos
r_x = 100
r_y = 300
# Bucle principal
jugador = True
while jugador:
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugador = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
P á g i n a 35 | 145
Cada vez que presionemos la tecla p
puntos += 1 la variable puntos se incrementará
en 1.
# Lógica
r_x += 1
if r_x > ANCHO: Cada vez que el cuadrado se
r_x = -100 salga de la ventana, la variable
vueltas se incrementará en 1.
vueltas += 1
# Dibujos
ventana.fill(NEGRO)
pygame.draw.rect(ventana, VERDE, (r_x, r_y, 100,
100))
ventana.blit(texto1, (260, 20)) Texto_puntos y texto_vueltas
ventana.blit(texto_puntos, (30, 20)) tendrán su respectivo texto
ventana.blit(texto_vueltas, (640, 20)) más su respectiva variable con
funciones de contador, borde
# Actualizar de la fuente suavizado y de
pygame.display.update() color blanco.
pygame.time.delay(5)
P á g i n a 36 | 145
11.- Cuadros (frames) por segundo
En esta capítulo vamos a ver como manejar la velocidad a la que se va mostrando las imágenes
de un juego.
La frecuencia con las que se van actualizando las imágenes en un juego, es decir los frames por
segundo.
P á g i n a 37 | 145
Este será el resultado:
Tenemos 50 cuadrados
que se mueven de arriba
hacia abajo en modo
diagonal.
P á g i n a 38 | 145
Hasta ahora lo que hemos hecho ha sido pausar el juego mediante la función delay del módulo
time a la que le pasábamos 10 milisegundos.
Vamos a ver otro forma de llevar esta tarea que además va a poder repercutir en otro aspectos
de los juegos.
P á g i n a 39 | 145
A la variable frames a su valor se le incrementa 1.
Creamos dos textos para poder visualizar en la pantalla los frames y el tiempo.
P á g i n a 40 | 145
import pygame
import random
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
# Inicializar
pygame.init()
ventana = pygame.display.set_mode((ANCHO, ALTO))
fuente = pygame.font.SysFont("arial", 64)
P á g i n a 41 | 145
El método reloj.tick() nos va a devolver
tiempo = reloj.tick() el tiempo que transcurre por cada
transcurrido += tiempo cambio de la ventana que se lo
frames +=1 pasaremos a la variable tiempo.
# Eventos
for event in pygame.event.get():
transcurrido + = tiempo, para que
if event.type == pygame.QUIT:
se vaya sumando el tiempo que
jugando = False vaya transcurriendo, entre
actualización y actualización.
# Lógica
A frames su valor se le incrementa
for c in cuadrados:
en 1.
c[0] += 1
c[1] += 2
if c[0] > 800:
c[0] = 0
if c[1] > 600:
c[1] = 0
# Imagenes
ventana.fill(NEGRO)
for c in cuadrados:
pygame.draw.rect(ventana, BLANCO, (c[0], c[1],
10, 10))
# Update
Insertamos dos textos, en uno
pygame.display.update() muestra los fotogramas por
pygame.time.delay(10) segundo y en el segundo los
segundos transcurridos.
pygame.quit()
Pausamos el juego
10 milisegundos.
P á g i n a 42 | 145
A la izquierda los cuadros por segundo y a la derecha los segundos transcurridos.
Si la CPU permite 100 0 150 FPS, las imágenes del juego cambiarán esas veces por segundo en
la memoria del ordenador, pero sólo se mostrarán las que permita el monitor.
No nos interesa que un juego vaya a tantos frames por segundo, por una parte porque va a ser
potencia desperdiciada ya que el monitor no va a poder mostrar.
Y por otra parte el juego no iría a la misma velocidad en dos ordenadores diferentes
dependiendo de la capacidad de la CPU de cada uno.
Vamos a poder controlar tasa de frames por segundo de un juego y de esta forma hacer que el
juego se vea igual en cualquier ordenador. Por lo tanto en el método reloj.tick() podemos pasarle
como argumento la cantidad de frames por segundo que queremos que tenga el juego.
P á g i n a 43 | 145
Vamos a cambiarlo a 30 y verás que va más despacio.
P á g i n a 44 | 145
Vamos a quitar los 30.
Vamos a por 10000 pero vamos a cambiar el color del texto en azul para poderlo ver.
P á g i n a 45 | 145
Por lo tanto cuando tenemos más imágenes el ordenador le cuesta más moverlas y bajan lo fps.
Nosotros lo dejaremos a 60 para aprovechar al máximo las capacidades del monitor y para no
desperdiciar recursos de la CPU.
Vamos a eliminar todo lo que no necesitaremos para el siguiente proyecto, para quedar de la
siguiente manera:
import pygame
import random
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
# Inicializar
pygame.init()
ventana = pygame.display.set_mode((ANCHO, ALTO))
fuente = pygame.font.SysFont("arial", 64)
reloj = pygame.time.Clock()
# Datos
cuadrados = []
for i in range(50):
x = random.randint(1, 799)
y = random.randint(1, 599)
P á g i n a 46 | 145
c = [x, y]
c = cuadrados.append(c)
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
# Lógica
for c in cuadrados:
c[0] += 1
c[1] += 2
if c[0] > 800:
c[0] = 0
if c[1] > 600:
c[1] = 0
# Imagenes
ventana.fill(NEGRO)
for c in cuadrados:
pygame.draw.rect(ventana, BLANCO, (c[0], c[1],
10, 10))
# Update
pygame.display.update()
pygame.quit()
P á g i n a 47 | 145
12.- Moviendo personajes en pygame
Ya hemos visto como hacer que una figura se mueva por la ventana en una dirección
determinada.
Vamos hacer ahora como se puede hacer para que sea el usuario el que mueva una figura
mediante las teclas.
import pygame
import random
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
NARANJA = (255, 128, 0) Definimos el color Naranja.
# Inicializar
pygame.init()
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
# Datos
aste_pos_x = -60
aste_pos_y = 70 Definimos las variables de las coordenadas de los
nave_pos_x = 400 dos cuadrados que agregaremos a la ventana.
nave_pos_y = 400
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
P á g i n a 48 | 145
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False Con las teclas derecha,
if event.key == pygame.K_RIGHT: izquierda, arriba y
nave_pos_x += 10 abajo controlaremos el
if event.key == pygame.K_LEFT: movimiento de un
cuadrado que se
nave_pos_x -= 10
desplazará 10 pixeles
if event.key == pygame.K_DOWN: en dirección a la flecha
nave_pos_y +=10 que seleccionemos
if event.key == pygame.K_UP:
nave_pos_y -= 10
# Lógica
aste_pos_x += 5 El cuadro de color Naranja de desplaza de
izquierda a derecha hasta desaparecer por la
if aste_pos_x > ANCHO: ventana y vuelve aparecer por la parte
aste_pos_x = - 60 izquierda, continuamente.
# Update
pygame.display.update()
pygame.quit()
El inconveniente es que para mover el cuadrado tenemos que apretar y soltar la tecla ya que si
la mantenemos apretada el cuadrado no se mueve, además el movimiento del cuadrado es poco
suave.
Ef = Ei + V x T
P á g i n a 49 | 145
Vamos a mejorar el código:
import pygame
import random
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
NARANJA = (255, 128, 0)
# Inicializar
pygame.init()
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
# Datos
aste_pos_x = -60
aste_pos_y = 70
aste_vel_x = 5
nave_pos_x = 400
nave_pos_y = 400
nave_vel_x = 0 Variables de velocidad
nave_vel_y = 0 de la nave.
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
P á g i n a 50 | 145
jugando = False
if event.key == pygame.K_RIGHT: Cuando presionamos
nave_vel_x = 10 las flechas.
if event.key == pygame.K_LEFT: KEYDOWN
nave_vel_x = -10
if event.key == pygame.K_DOWN:
nave_vel_y = 10
if event.key == pygame.K_UP:
nave_vel_y = -10
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
if event.key == pygame.K_DOWN: Cuando dejamos de
nave_vel_y = 0 presionar las flechas.
if event.key == pygame.K_UP: KEYUP
nave_vel_y = 0
# Lógica
aste_pos_x += aste_vel_x La nave que se desplaza sola de
if aste_pos_x > ANCHO: izquierda a derecha.
aste_pos_x = - 60
El valor de las variables nave_vel_x
nave_pos_x += nave_vel_x y nave_vel_y según el usuario
nave_pos_y += nave_vel_y mantenga o no presionada las
flechas del teclado.
# Update
pygame.display.update() Los valores de las variables nave_pos_x
y nave_pos_y las controla el usuario con
las teclas de dirección del teclado.
pygame.quit()
P á g i n a 51 | 145
P á g i n a 52 | 145
13.- Cambiando orientación de las figuras
Este será el código:
import pygame
import random
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
NARANJA = (255, 128, 0)
# Funciones
def nave_arriba(superficie, x ,y):
pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x, y, 15, 30))
pygame.draw.rect(superficie, NEGRO, (x + 45, y, 15,
30))
P á g i n a 53 | 145
pygame.draw.rect(superficie, NEGRO, (x, y+45, 30,
15))
# Inicializar
pygame.init()
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
# Datos
aste_pos_x = -60
aste_pos_y = 70
aste_vel_x = 5
nave_pos_x = 400
nave_pos_y = 400
nave_vel_x = 0
nave_vel_y = 0
La variable direccion guarda la dirección
direccion = "arriba" que le asignaremos según la tecla de
dirección que presionemos del teclado.
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
if event.key == pygame.K_RIGHT:
direccion = "derecha"
nave_vel_x = 10
if event.key == pygame.K_LEFT:
direccion = "izquierda"
nave_vel_x = -10
if event.key == pygame.K_DOWN:
direccion = "abajo"
P á g i n a 54 | 145
nave_vel_y = 10
if event.key == pygame.K_UP:
direccion = "arriba"
nave_vel_y = -10
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
if event.key == pygame.K_DOWN:
nave_vel_y = 0
if event.key == pygame.K_UP:
nave_vel_y = 0
# Lógica
aste_pos_x += aste_vel_x
if aste_pos_x > ANCHO:
aste_pos_x = - 60
nave_pos_x += nave_vel_x
nave_pos_y += nave_vel_y
# Dibujos
ventana.fill(NEGRO)
import pygame
import random
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
NARANJA = (255, 128, 0)
# Funciones
def nave_arriba(superficie, x ,y):
pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x, y, 15, 30))
pygame.draw.rect(superficie, NEGRO, (x + 45, y, 15,
30))
# Inicializar
pygame.init()
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
# Datos
aste_pos_x = -60
aste_pos_y = 70
aste_vel_x = 5
nave_pos_x = 400
nave_pos_y = 400
nave_vel_x = 0
nave_vel_y = 0
P á g i n a 58 | 145
direccion = "arriba"
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
if event.key == pygame.K_RIGHT:
direccion = "derecha"
nave_vel_x = 10
if event.key == pygame.K_LEFT:
direccion = "izquierda"
nave_vel_x = -10
if event.key == pygame.K_DOWN:
direccion = "abajo"
nave_vel_y = 10
if event.key == pygame.K_UP:
direccion = "arriba"
nave_vel_y = -10
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
if event.key == pygame.K_DOWN:
nave_vel_y = 0
if event.key == pygame.K_UP:
nave_vel_y = 0
# Lógica
aste_pos_x += aste_vel_x
if aste_pos_x > ANCHO:
P á g i n a 59 | 145
aste_pos_x = - 60
Según el valor de contador
nave_pos_x += nave_vel_x según las siguientes
nave_pos_y += nave_vel_y condiciones llamará a una
función u otra.
contador += 1
if contador >= 41:
contador = 1
if contador < 11:
asteroide_1(ventana, aste_pos_x, aste_pos_y)
elif contador < 21:
asteroide_2(ventana, aste_pos_x, aste_pos_y)
elif contador < 31:
asteroide_3(ventana, aste_pos_x, aste_pos_y)
elif contador < 41:
asteroide_4(ventana, aste_pos_x, aste_pos_y)
if direccion == "arriba":
nave_arriba(ventana, nave_pos_x, nave_pos_y)
elif direccion == "abajo":
nave_abajo(ventana, nave_pos_x, nave_pos_y)
elif direccion == "derecha":
nave_derecha(ventana, nave_pos_x, nave_pos_y)
elif direccion == "izquierda":
nave_izquierda(ventana, nave_pos_x, nave_pos_y)
# Update
pygame.display.update()
pygame.quit()
P á g i n a 60 | 145
15.- Colisiones en pygame
En este capítulo vamos a ver como hacer que dos objetos choquen.
Para entender las colisiones vamos a analizar este esquema en que vamos a tener el cuadrado
naranja y el cuadrado verde.
Las coordenadas del cuadrado naranja x + x + ancho y de la y hasta la y + ancho, igualmente las
coordenadas del cuadrado verde.
import pygame
# Inicializar
pygame.init()
reloj = pygame.time.Clock()
# Medidas
ANCHO = 800
ALTO = 600
# Colores
BLANCO = (255,255,255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)
P á g i n a 61 | 145
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
NARANJA = (255, 128, 0)
# Funciones
def nave(superficie, x, y, ancho, alto):
pygame.draw.rect(superficie, VERDE, (x, y, ancho,
alto))
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
# Datos
aste_ancho = 60
aste_alto = 60
aste_pos_x = 100
aste_pos_y = 100
aste_vel_x = 5
nave_ancho = 60
nave_alto = 60
nave_pos_x = 600
nave_pos_y = 500
nave_vel_x = 0
nave_vel_y = 0
# Bucle principal
reloj.tick(60)
jugando = True
while jugando:
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
if event.key == pygame.K_RIGHT:
nave_vel_x = 10
P á g i n a 62 | 145
if event.key == pygame.K_LEFT:
nave_vel_x = -10
if event.key == pygame.K_DOWN:
nave_vel_y = 10
if event.key == pygame.K_UP:
nave_vel_y = -10
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
if event.key == pygame.K_DOWN:
nave_vel_y = 0
if event.key == pygame.K_UP:
nave_vel_y = 0
# Lógica
aste_pos_x += aste_vel_x
if aste_pos_x > ANCHO:
aste_pos_x =- aste_ancho
nave_pos_x += nave_vel_x
nave_pos_y += nave_vel_y
# Dibujos
ventana.fill(NEGRO)
asteroide(ventana, aste_pos_x, aste_pos_y,
aste_ancho, aste_alto)
nave(ventana, nave_pos_x, nave_pos_y, nave_ancho,
nave_alto)
# Actualizar
pygame.display.update()
pygame.time.delay(10)
# Salir
pygame.quit()
P á g i n a 63 | 145
Este es el código que hemos agreagado:
Línea 79
>
P á g i n a 64 | 145
Línea 80
<
Línea 81
>
P á g i n a 65 | 145
Línea 82
<
Sumamos + 20 para que los dos objetos se interpongan 20 pixeles entre ellos.
P á g i n a 66 | 145
16.- Cargando imágenes
Hasta ahora solamente hemos estado utilizando figuras y dibujos, pero si queremos dar una
estética más interesante a nuestro juegos no va hacer falta utilizar imágenes, que hayamos
diseñador nosotros o las que tengamos a nuestra disposición para poder ponerlas en los juegos.
Vamos a ver como podemos cargar las imágenes y utilizarlas en juego con pygame.
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
NARANJA = (255, 128,0)
VERDE = (0, 255, 0)
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
P á g i n a 67 | 145
# Imagenes
ventana.fill(NEGRO)
pygame.draw.rect(ventana, NARANJA, (200, 200, 60,
60))
pygame.draw.rect(ventana, VERDE, (600, 500, 60,
60))
pygame.display.update()
pygame.quit()
Ahora lo que queremos hacer es en vez de rellenar de negro la ventana queremos poner un
fondo.
En lugar del cuadrado naranja un asteroide y en lugar del cuadro verde una nave.
P á g i n a 68 | 145
Vamos a cambiar las dimensiones que tienen que coincidir con las dimensiones de la ventana.
P á g i n a 69 | 145
También lo guardamos como PNG.
Otros programas que podemos utilizar que son totalmente gratuitos son el Gimp y el Krita.
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
NARANJA = (255, 128,0)
VERDE = (0, 255, 0)
# Imágenes
fondo = pygame.image.load("fondo.png")
# Bucle principal
jugando = True Creamos un objeto de tipo imagen
while jugando: llamado fondo, para cargar la imagen
desde nuestro ordenador, si esta se
encontrarse en una carpeta, habría
reloj.tick(60)
que indicar la ruta.
# Eventos
for event in pygame.event.get():
P á g i n a 70 | 145
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
Para insertar el fondo en la ventana
utilizaremos el método blit, llamando al
# Imagenes objeto y dándole las cooredendas.
ventana.blit(fondo,(0,0))
pygame.quit()
P á g i n a 71 | 145
Vamos a eliminar los dos cuadrados.
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
NARANJA = (255, 128,0)
VERDE = (0, 255, 0)
# Imágenes
fondo = pygame.image.load("fondo.png")
asteroide_1A = pygame.image.load("asteroideA_1.png")
# Si el dibujo muestra los bordes blancos.
asteroide_1A.set_colorkey(BLANCO)
# los demas los hemos realizado con Krita
asteroide_2A = pygame.image.load("asteroideB_1.png")
nave_arriba = pygame.image.load("nave_arriba.png")
P á g i n a 72 | 145
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
# Imagenes
ventana.blit(fondo,(0,0))
ventana.blit(asteroide_1A, (200, 100))
ventana.blit(asteroide_2A, (600, 400))
ventana.blit(nave_arriba, (500, 500))
pygame.display.update()
Cargamos el fondo y las correspondientes
pygame.quit() imágenes en la ventana, con sus correspondientes
coordenadas.
P á g i n a 73 | 145
17.- Usar método convert con las imágenes en pygame
En el capitulo anterior vimos como cargar imagen y mostrarlas en la ventana de un juego.
Lo que hicimos fue cargar una imagen para el fondo, mediante la función load e hicimos lo
mismo para un asteroide grande y otro pequeño, además de la nave.
Si la imagen la realizamos con el Paint estas no tienen transparencias, tendremos que utilizar
el método .set_colorkey(Color que se convierte a transparencia).
Las imágenes realizadas con Kryta permiten las transparencias, ello implica que nos podemos
saltar este paso.
Para el próximo capítulo vamos utilizando esta plantilla para ir haciendo el siguiente juego:
Una nave que podemos mover y que tiene que traspasar una serie de cinturones de asteroides,
pero antes de llevarlo a cabo vamos a ver unos métodos que nos va a permitir dar más eficiencia
a los juegos a la hora de poner las imágenes en la ventana y vamos a realizar algunas pruebas
para ver hasta que punto la fluidez de los juegos depende de que la imagen contengan o no
transparencia.
P á g i n a 74 | 145
El método convert, que nos va a permitir y convertir el formato de píxeles con el que se guarda
las imágenes en memoria de tal forma que luego para el interprete de Python sea más rápido
mostrarlas en la ventana.
Como dice la documentación de pygame este va a ser el formato con el que más rapidez se van
a colocar las imágenes. Por lo tanto es una buena idea convertir las superficies antes de que se
vaya a poner en la ventana muchas veces, y también nos indica que si la superficie tiene pixeles
alpha, tienen transparencia habrá que usar el método convert_alpha() para preservar esos
pixeles.
P á g i n a 75 | 145
Sin método Con método
convert convert
Imágenes sin
transparencia 40 80
Imágenes con
transparencia 30 120
Hemos quitado el límite de fps y a continuación vamos a comprobar los fps con el método
ger_fps(), sin tener que hacer cálculos.
P á g i n a 76 | 145
18.- Añadiendo figuras
Seguimos con el juego de los asteroides, vamos a ver como podemos poner distintos asteroides
en al ventana del juego cada uno con su velocidad, cada uno con su orden de rotación y si la
nave choca con uno se produzca la colisión.
Adjuntamos código:
import pygame
import random
# Inicializar
pygame.init()
# Funciones
def colision(x1, y1, a1, b1, x2, y2, a2, b2, ex=0):
if x1 + a1 > x2 + ex and \
x1 + ex < x2 + a2 and \
y1 + b1 > y2 + ex and \
y1 + ex < y2 + b2:
return True
else:
return False
# Carga Imágenes
fondo = pygame.image.load("fondo.png").convert()
nave_arr =
pygame.image.load("nave_arriba.png").convert_alpha()
nave_abj =
pygame.image.load("nave_abajo.png").convert_alpha()
P á g i n a 77 | 145
nave_izq =
pygame.image.load("nave_izquierda.png").convert_alpha()
nave_der =
pygame.image.load("nave_derecha.png").convert_alpha()
aste_1a =
pygame.image.load("asteroideA_1.png").convert_alpha()
aste_1b =
pygame.image.load("asteroideA_2.png").convert_alpha()
aste_1c =
pygame.image.load("asteroideA_3.png").convert_alpha()
aste_1d =
pygame.image.load("asteroideA_4.png").convert_alpha()
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
jugando = False
if event.key == pygame.K_RIGHT:
direccion = "derecha"
nave_vel_x = 2
if event.key == pygame.K_LEFT:
direccion = "izquierda"
nave_vel_x = -2
if event.key == pygame.K_DOWN:
direccion = "abajo"
nave_vel_y = 2
if event.key == pygame.K_UP:
direccion = "arriba"
nave_vel_y = -2
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
if event.key == pygame.K_DOWN:
nave_vel_y = 0
if event.key == pygame.K_UP:
nave_vel_y = 0
# Lógica Este ciclo recorre todos los
for a in asteroides_grandes: asteroides , suma la velocidad, es
a[1]+= a[3] para que se vaya desplazando
if a[1] > ANCHO: hacia la derecha.
a[1] = -64 Con el if controlamos que cuando
llega al final del acho de al
nave_pos_x += nave_vel_x ventana retorne al principio.
nave_pos_y += nave_vel_y
for a in asteroides_grandes:
if colision(a[1], a[2], 64, 64, nave_pos_x,
nave_pos_y, 32, 32, 15):
jugando = False
# Imagenes
ventana.blit(fondo,(0,0))
texto1 = fuente.render("Nivel: " + str(nivel),
True, BLANCO)
texto2 = fuente.render("Vidas: " + str(vidas),
True, BLANCO)
ventana.blit(texto1, (20,10)) Controla la rotación de los
ventana.blit(texto2, (1150, 10)) asteroides
frames_asteroides += 1
if frames_asteroides >= 41:
frames_asteroides = 1
P á g i n a 80 | 145
if direccion == "arriba":
ventana.blit(nave_arr, (nave_pos_x,
nave_pos_y))
if direccion == "abajo":
ventana.blit(nave_abj, (nave_pos_x,
nave_pos_y))
if direccion == "izquierda":
ventana.blit(nave_izq, (nave_pos_x,
nave_pos_y))
if direccion == "derecha":
ventana.blit(nave_der, (nave_pos_x,
nave_pos_y))
pygame.display.update()
Controla la dirección de la nave.
pygame.quit()
P á g i n a 81 | 145
19.- Poniendo niveles
En este capítulo vamos a implementar una ventana de introducción y varios niveles de juego.
P á g i n a 82 | 145
Antes de seguir con el juego vamos a ver un esquema para entender un poco la lógica del juego,
antes de ver el código.
Vamos a tener dos bucles lógicos y dentro de los bucles lógicos para mantener las ventanas de
pygame.
Una vez empezamos el juego entramos en while en_juego donde entraremos a un segundo
bucle llamado while en_inicio donde veremos la presentación y a continuación entraremos en
un tercer bucle donde empieza la partida, donde entramos a otro bucle para los niveles del juego
y por último el bucle final.
P á g i n a 83 | 145
en_juego = True
while en_juego:
num_vidas = 3
num_nivel = 1
en_partida = False
en_inicio = True
while en_inicio:
# Evento Entrar: en_partida = True
# Evento Cerrar ventana:
# en_inicio = False
# en_juego = False
pass
while en_partida:
en_final = False
# Se cran los asteroides según el nivel
en_nivel = True
while en_nivel:
if # colision:
num_vidas -= 1
en_nivel = False
if # llegar arriba:
num_nivel += 1
en_nivel = False
if num_vidas == 0:
en_final = True
if num_nivel > 3:
en_final = True
while en_final:
P á g i n a 84 | 145
# Evento Cerrar ventana o no jugar más:
# en_final = False
# en_partida = False
# en_juego = False
# Evento jugar de nuevo:
# en_final = False
# en_partida = False
if ganando:
# Mensaje: Se ha ganado
else:
# Mensaje: Se ha perdido
import pygame
import random
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
# Funciones
def colision(x1, y1, a1, b1, x2, y2, a2, b2, ex=0):
if x1 + a1 > x2 + ex and \
x1 + ex < x2 + a2 and \
y1 + b1 > y2 + ex and \
y1 + ex < y2 + b2:
return True
else:
return False
P á g i n a 85 | 145
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
fuente1 = pygame.font.SysFont("arial black", 24)
fuente2 = pygame.font.SysFont("Segoe print", 32)
# Carga imágenes
fondo = pygame.image.load("fondo.png").convert()
nave_arr =
pygame.image.load("nave_arriba.png").convert_alpha()
nave_abj =
pygame.image.load("nave_abajo.png").convert_alpha()
nave_izq =
pygame.image.load("nave_izquierda.png").convert_alpha()
nave_der =
pygame.image.load("nave_derecha.png").convert_alpha()
aste_1a =
pygame.image.load("asteroideA_1.png").convert_alpha()
aste_1b =
pygame.image.load("asteroideA_2.png").convert_alpha()
aste_1c =
pygame.image.load("asteroideA_3.png").convert_alpha()
aste_1d =
pygame.image.load("asteroideA_4.png").convert_alpha()
aste_2a =
pygame.image.load("asteroideB_1.png").convert_alpha()
aste_2b =
pygame.image.load("asteroideB_2.png").convert_alpha()
aste_2c =
pygame.image.load("asteroideB_3.png").convert_alpha()
aste_2d =
pygame.image.load("asteroideB_4.png").convert_alpha()
# Bucle principal
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
en_inicio = False
en_partida = True
P á g i n a 87 | 145
" Pulsa 'ENTER' para
empezar"
]
y = 80
for frase in historia:
texto = fuente2.render(frase, True, BLANCO)
ventana.blit(texto, (150, y))
y += 80
pygame.display.update()
num_aste_grandes = num_nivel * 5
num_aste_pequenios = num_nivel * 10
asteroides_grandes = []
asteroides_pequenios = []
for i in range(num_aste_grandes):
x = random.randint(0, ANCHO)
y = random.randint(50, ALTO-120)
v = random.randint(1, 3)
f = random.choice([aste_1, aste_3, aste_4,
aste_5])
a = [f, x, y, v]
asteroides_grandes.append(a)
for i in range(num_aste_pequenios):
x = random.randint(0, ANCHO)
y = random.randint(50, ALTO-120)
v = random.randint(1, 4)
f = random.choice([aste_2, aste_6, aste_7,
aste_8])
a = [f, x, y, v]
asteroides_pequenios.append(a)
P á g i n a 88 | 145
asteroides = asteroides_grandes +
asteroides_pequenios
nave_pos_x = 600
nave_pos_y = 670
nave_vel_x = 0
nave_vel_y = 0
direccion = "arriba"
frames_asteroides = 0
Variable en_nivel igual
a True
en_nivel = True
while en_nivel: Bucle en_nivel
# Eventos
for event in pygame.event.get(): Variables en_nivel,
if event.type == pygame.QUIT: en_partida y en_juego
en_nivel = False a False.
en_partida = False
en_juego = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
direccion = "derecha"
nave_vel_x = 2
if event.key == pygame.K_LEFT:
Eventos de direccion = "izquierda"
moverse
nave_vel_x = -2
if event.key == pygame.K_DOWN:
direccion = "abajo"
nave_vel_y = 2
if event.key == pygame.K_UP:
direccion = "arriba"
nave_vel_y = -2
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
P á g i n a 89 | 145
if event.key == pygame.K_DOWN:
nave_vel_y = 0
if event.key == pygame.K_UP:
nave_vel_y = 0
# Lógica
for a in asteroides_grandes:
a[1] += a[3]
if a[1] > ANCHO:
a[1] = -64
for a in asteroides_pequenios:
a[1] += a[3]
if a[1] > ANCHO:
a[1] = -32
nave_pos_x += nave_vel_x
nave_pos_y += nave_vel_y
for a in asteroides_grandes:
if colision(a[1], a[2], 64, 64,
nave_pos_x, nave_pos_y, 32, 32, 15):
en_nivel = False
num_vidas -= 1
for a in asteroides_pequenios:
if colision(a[1], a[2], 32, 32,
nave_pos_x, nave_pos_y, 32, 32, 15):
P á g i n a 90 | 145
en_nivel = False
num_vidas -= 1
if num_vidas == 0:
ganando = False Número de vidas
en_final = True
if num_nivel > 3:
ganando = True Número de nivel
en_final = True
# Imágenes
ventana.blit(fondo, (0,0))
frames_asteroides += 1
if frames_asteroides >= 41:
frames_asteroides = 1
if direccion == "arriba":
P á g i n a 91 | 145
ventana.blit(nave_arr, (nave_pos_x,
nave_pos_y))
elif direccion == "abajo":
ventana.blit(nave_abj, (nave_pos_x,
nave_pos_y))
elif direccion == "izquierda":
ventana.blit(nave_izq, (nave_pos_x,
nave_pos_y))
elif direccion == "derecha":
ventana.blit(nave_der, (nave_pos_x,
nave_pos_y))
pygame.display.update()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_n:
Variable en_final, en_partida en_final = False
y en_juego igual a False en_partida = False
en_juego = False
if event.key == pygame.K_s:
Evento jugar de
en_final = False
nuevo
en_partida = False
ventana.fill(NEGRO)
historia_perdido = [
" No has conseguido llegar a
Júpiter. Los cinturones",
" de asteroides han destruido tu
nave. Pero has tenido",
P á g i n a 92 | 145
" suerte y te han recogido unos
chatarreros del espacio.",
" ¿Quieres volverlo a intentar a borde
de una nueva nave?",
"",
" Pulsa 's' para volverlo
a intentar",
" Pulsa 'n' para salir del
juego"]
historia_ganado = [
" Has conseguido llegar a Júpiter y
completar tu misión.",
" Los cinturones de asteroides no han
conseguido pararte.",
" Te has convertido en un héroe
del espacio.",
" ¿Quieres embarcarte en una
nueva misión?",
"",
" Pulsa 's' para volver a
jugar",
" Pulsa 'n' para salir del
juego"]
Mensaje que se
muestra cuando has
if ganando: ganado o cuando has
historia = historia_ganado perdido.
else:
historia = historia_perdido
y = 80
for frase in historia:
texto = fuente2.render(frase, True,
BLANCO)
ventana.blit(texto, (150, y))
y += 80
pygame.display.update()
pygame.quit()
P á g i n a 93 | 145
20.- Clase Rect en pygame
Hasta ahora hemos visto las características más básicas de pygame, la herramientas más
elementales.
Pygame dispone de herramientas más avanzadas, más optimizadas para poder llevar al cabo
juegos de una forma más eficiente, entre estas herramientas están algunas clases que vienen
predefinidas en la librería pygame, como la clase que vamos a ver en este capítulo.
La clase Rect ya la tenemos predefinida en la librería pygame por lo tanto será únicamente
usarla.
Atributos (Datos)
Clase: Métodos (Funciones)
r1.x = 10 (Atributos x)
r1 = Rect() r1.x = 20
r1.colliderect(r2) (Mletodo
22 = Rect() Colliderect)
Vamos a ver mucho la programación orientada a objeto, pero si debemos de tener una nociones
como que las clases constan de atributos y métodos, y para acceder a los atributos o llamar a
los métodos hemos de usar la notación del punto.
P á g i n a 94 | 145
Este será el resultado:
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
NEGRO = (0, 0, 0)
AZUL = (0, 0, 255)
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
P á g i n a 95 | 145
# Datos
nave_pos_x = 400
nave_pos_y = 500
nave_vel_x = 0
nave_vel_y = 0
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
nave_vel_x = 5
if event.key == pygame.K_LEFT:
nave_vel_x = -5
if event.key == pygame.K_DOWN:
nave_vel_y = 5
if event.key == pygame.K_UP:
nave_vel_y = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
nave_vel_x = 0
if event.key == pygame.K_LEFT:
nave_vel_x = 0
if event.key == pygame.K_DOWN:
nave_vel_y = 0
if event.key == pygame.K_UP:
nave_vel_y = 0
# Lógica
nave_pos_x += nave_vel_x
nave_pos_y += nave_vel_y
# Dibujos
ventana.fill(NEGRO)
pygame.draw.rect(ventana, AZUL,
(nave_pos_x,nave_pos_y, 50, 50))
# Actualizar
pygame.display.update()
# Salir
pygame.quit()
En datos creamos el objeto nave, y los valores para el alto y ancho ya no son necesarios.
Lo mismo.
P á g i n a 97 | 145
Al dibujar el rectángulo poniendo nave ya sabe las coordenadas y la dimensiones.
Antes necesitábamos :
pygame.draw.rect(ventana, AZUL, (nave_pos_x,nave_pos_y, 50, 50))
Le damos a ejecutar:
Ya nos podemos mover en todas las dirección, pero sin salir de la ventana, cuando llega a un
extremo de ella el cuadrado no sigue.
Añadir a este programa otro objeto de la clase Rect que pueda ser una roca y se sitúa en el
centro de la ventana, de tal forma que si la nave colisiona con la roca coloque la nave en sus
coordenadas iniciales y se trata de utilizar el método de la clase Rect colliderect().
P á g i n a 98 | 145
21.- Método colliderect de la clase Rect.
En el apartado de Datos creamos un nuevo objeto llamado roca.
Las variables nave_vel_x y nave_vel_y son las que utilizamos para mover nuestro objeto.
P á g i n a 99 | 145
De esta forma este método nos va a permitir implementar modos o paredes, caminos que
limiten el movimiento de los objetos en los juegos.
Para el próximo capitulo vamos a poner 4 muros en uno de los lados de la ventana y que el
personaje al colisionar con cualquiera de ellos se pare frente al muro y no pueda avanzar.
P á g i n a 100 | 145
22.- Muros con pygame
En el capítulo anterior hemos visto cómo podemos utilizar el método colliderect() de la clase
Rect para implementar muros en los juegos.
En capítulo anterior creamos un objeto de la clase Rect una nave y otro roca y si la nave
colisionaba con la roca, volvíamos a restar la velocidad a la nave para que no se movise, se
quedase en el mismo sitio.
Vamos a empezar:
P á g i n a 101 | 145
Lo adaptamos para el nuevo personaje.
Con el siguiente código controlamos que nuestro personaje no teque ninguno de los muros.
P á g i n a 102 | 145
Cambiamos la variable nave_vel_ por personaje_vel_ en todo este bloque de código.
Un detalle a tener en cuenta, tanto la velocidad del personaje que es 5 como la posición de los
muros que todos los valores son múltiplos de 5 hace que la colisión sea perfecta, si cambiásemos
la velocidad de nuestro personaje a 7 como la ubicación de los muros no serían múltiplos de 7
podemos observar que hay una pequeña separación entre el muro y el personaje.
P á g i n a 103 | 145
En la variable dirección almacenamos al tecla que estamos presionando.
En el apartado de lógica según en la dirección que vaya nos detendremos en la parte opuesta
del muro.
P á g i n a 104 | 145
Ya no podemos hacer movimientos en diagonal.
P á g i n a 105 | 145
23.- Mapas con pygame
En el capítulo anterior hemos visto como poner muros en la ventana de un juego pero puede
que queramos hacer un juego de plataformas o que contenga muchas habitaciones y que por lo
tanto necesitemos un método mejor y más rápido para llevarlo a cabo, vamos a ver como lo
podemos hacer mediante mapas.
Vamos a partir de la plantilla del capítulo anterior en la que simplemente tenemos dibujados 4
muros y tenemos un personaje que se puede ir moviendo por la ventana a la que le hemos dado
velocidad 10, para que las colisiones sean más ajustadas y hemos utilizado el primer algoritmo
que vimos en el capítulo anterior.
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
NEGRO = (0, 0, 0)
AZUL = (0, 0, 255)
VERDE =(0, 255, 0)
MARRON =(128, 64, 0)
# Funciones
def dibujar_muro(superficie, rectangulo):
pygame.draw.rect(superficie, MARRON, rectangulo)
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
# Datos
muros = [
pygame.Rect(500, 100, 300, 100),
pygame.Rect(200, 200, 100, 300),
pygame.Rect(500, 500, 300, 100),
pygame.Rect(1000, 200, 100, 300)]
P á g i n a 106 | 145
personaje = pygame.Rect(600, 400, 50, 50)
personaje_vel_x = 0
personaje_vel_y = 0
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
direccion ="derecha"
personaje_vel_x = 10
if event.key == pygame.K_LEFT:
direccion = "izquierda"
personaje_vel_x = -10
if event.key == pygame.K_DOWN:
direccion = "abajo"
personaje_vel_y = 10
if event.key == pygame.K_UP:
direccion = "arriba"
personaje_vel_y = -10
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
personaje_vel_x = 0
if event.key == pygame.K_LEFT:
personaje_vel_x= 0
if event.key == pygame.K_DOWN:
personaje_vel_y = 0
if event.key == pygame.K_UP:
P á g i n a 107 | 145
personaje_vel_y = 0
# Lógica
personaje.x += personaje_vel_x
personaje.y += personaje_vel_y
dibujar_personaje(ventana, personaje)
# Actualizar
pygame.display.update()
# Salir
pygame.quit()
P á g i n a 108 | 145
Vamos a ver como poder poner más muros de forma más eficiente.
Creamos el correspondiente mapa, para que sean las baldosas de la ventana del juego.
Si dividimos 1280 entre 80 nos dará 16 y si dividimos 720 entre 80 nos dará 9 es decir 16 x 9.
Si queremos poner más baldosas 1280 entre 40 serán 32 y 720 entre 40 será 18 es decir 32 x 18.
P á g i n a 109 | 145
Vamos a crear otra función:
P á g i n a 110 | 145
Código completo:
import pygame
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
NEGRO = (0, 0, 0)
AZUL = (0, 0, 255)
VERDE =(0, 255, 0) Esta función dibuja un rectángulo
de color marrón, de un objeto de
MARRON =(128, 64, 0)
tipo Rect.
# Funciones
def dibujar_muro(superficie, rectangulo):
pygame.draw.rect(superficie, MARRON, rectangulo)
def construir_mapa(mapa):
Esta función con el parámetro mapa.
muros = [] Definimos una lista llamada muros vacía,
x = 0 definimos dos variables x e y con el valor 0,
y = 0 en este ejemplo mapa realizará un recorrido
for fila in mapa: entre 0 y 8 en el primer bucle y a
for muro in fila: continuación con el siguiente bucle anidado
if muro == "X":
muros.append(pygame.Rect(x, y, 80, 80))
x += 80
x = 0 fila en este caso es entre 0 y 15 las 16 filas. Si muro es igual
y += 80 a “X” lo añades a la lista muros como un objeto Rect con
los valores x e y con dimensiones 80 x 80.
return muros
# Mapas
P á g i n a 111 | 145
mapa = [
"XXXXXXXXXXXXXXXX", Creamos una lista llamada mapa
"X X", donde dibujamos con X como
"X XXXXXX XXXXX X", queremos que sean los muros, en
este caso con unas dimensiones
"X X X",
de 16 x 9.
"X XXXX XXXXXXX X",
"X X X X",
"X XX XXXXX XXX X",
"X X",
"XXXXXXXXXXXXXXXX"
]
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
direccion ="derecha"
P á g i n a 112 | 145
personaje_vel_x = 10
if event.key == pygame.K_LEFT:
direccion = "izquierda"
personaje_vel_x = -10
if event.key == pygame.K_DOWN:
direccion = "abajo"
personaje_vel_y = 10
if event.key == pygame.K_UP:
direccion = "arriba"
personaje_vel_y = -10
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
personaje_vel_x = 0
if event.key == pygame.K_LEFT:
personaje_vel_x= 0
if event.key == pygame.K_DOWN:
personaje_vel_y = 0
if event.key == pygame.K_UP:
personaje_vel_y = 0
# Lógica
personaje.x += personaje_vel_x
personaje.y += personaje_vel_y
P á g i n a 113 | 145
Llama a la función dibujar_mapa, como
parámetros en la ventana que tiene
que ir y muros que es la lista con todas
dibujar_mapa(ventana, muros) las baldosas.
# Actualizar
pygame.display.update()
# Salir
pygame.quit()
P á g i n a 114 | 145
24.- Método collidepoint
Vamos a seguir viendo las posibilidades que nos ofrece los mapas para hacer juegos en
pygame.
import pygame
# Incializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
NEGRO = (0, 0, 0)
VERDE = (0, 255, 0)
AZUL = (0, 0, 255)
CLARO = (200, 165, 120)
MARRON = (120, 60, 20)
# Mapas
mapa = [
"XXXXXXXXXXXXXXXX",
"XXXFXXXXXXXXXFXX",
Este mapa tiene dos letras, la X para
"X X", el muro y la F para las manzanas.
"X XXXXXX XXXXX X",
"X XXXFXX FXXX X",
"X XXX XX XXXXF X",
"X X",
"XXXXXXFXXXXXXXXX",
"XXXXXXXXXXXXXXXX" Creamos una función para
] dibujar también las manzanas.
# Funciones
def dibujar_muro(superficie, rectangulo):
pygame.draw.rect(superficie, MARRON, rectangulo)
def construir_mapa(mapa):
Tenemos dos listas vacías muros y
muros = []
manzanas, según baldose detecte
manzanas = [] kuna X o una F lo agregará a la
x = 0 correspondiente lista.
y = 0
for fila in mapa:
for baldosa in fila:
if baldosa == "X":
muros.append(pygame.Rect(x, y, 80, 80))
if baldosa == "F":
manzanas.append(pygame.Rect(x, y, 80,
80))
x += 80
x = 0
y += 80
return muros, manzanas Retorna dos listas.
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
La función dibujar_mapa
# Datos ahora le pasamos un
muros, manzanas = construir_mapa(mapa) argumento de más para
llamar a dos funciones,
personaje = pygame.Rect(100, 400, 40, 40) dibujar_muro y
personaje_vel_x = 0 dibujar_manzana
personaje_vel_y = 0
La función
# Bucle principal construir_mapa(mapa) retorna
jugando = True dos valores que almacenaremos
while jugando: en las listas muros y manzanas.
reloj.tick(60)
# Eventos
P á g i n a 116 | 145
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
personaje_vel_x = 2
if event.key == pygame.K_LEFT:
personaje_vel_x = -2
if event.key == pygame.K_DOWN:
personaje_vel_y = 2
if event.key == pygame.K_UP:
personaje_vel_y = -2
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
personaje_vel_x = 0
if event.key == pygame.K_LEFT:
personaje_vel_x = 0
if event.key == pygame.K_DOWN:
personaje_vel_y = 0
if event.key == pygame.K_UP:
personaje_vel_y = 0
Para controla cuando el
# Lógica personaje detecta una manzana
utilizaremos el método
personaje.x += personaje_vel_x
collidepoint de este modo le
personaje.y += personaje_vel_y decimos que punto de la
manzana tiene que tocar.
for muro in muros:
if personaje.colliderect(muro):
personaje.x -= personaje_vel_x
personaje.y -= personaje_vel_y
# Salir
pygame.quit()
P á g i n a 118 | 145
25.- La clase Surface de pygame
En este capítulo vamos a ver otra clase predefinida que viene el la librería pygame que nos va a
facilitar mucho la codificación de nuestros juegos.
Ya hemos visto la clase Rect que nos permite crear un objeto de tipo Rect y pasársela
directamente a la función rect, para dibujar un rectángulo.
En este capítulo vamos a ver la clase Surface (superficie) que ya la hemos utilizado porque ya
hemos creado objetos de tipo superficie mediante algunas funciones esenciales que hemos
tenido de utilizar en nuestros juegos, por ejemplo la función .set_mode().
Si hacemos un print(ventna) para que nos muestre que tipo de objeto es.
Bueno pues no solo vamos utilizar las superficies a la hora de crear la ventana del juego,
podemos crear superficies directamente mediante la clase Surface.
Por ejemplo:
print(manzana)
Nos pega una superficie, pero por defecto tiene el color negro.
P á g i n a 119 | 145
manzana.fill(ROJO)
Sobre esta superficie podemos hacer dibujos, cargar imágenes, podríamos llevar a cabo
diferentes opciones al igual que lo podemos hacer con la superficie ventana.
Para que nos puede servir este objeto de la clase superficies si ya podíamos dibujar un cuadrado
perfectamente, pues esta clase va a tener muchos métodos que nos pueden facilitar la
codificación.
Si nacemos un dir(pygame.Surface)
Veremos los métodos que tenemos a nuestra disposición para manejar Surface.
P á g i n a 120 | 145
El que nos va a interesar en este capítulo van a ser el método get.rect, con este método no va a
permitir obtener un objeto de tipo rectángulo que contenga las coordenadas y las medidas de
esta superficie.
Ejemplo:
manzana_rect = manzana.get_tect()
<rect(0,0,50,50)>
Un objeto de tipo rectángulo que se sitúa por defecto en las coordenadas o,o y que sus
dimensiones son 50 de ancho por 50 de alto.
Por lo tanto este método nos puede permitir muy fácilmente situar superficies en la ventana y
poder manejar sus coordenadas de una forma sencilla.
Vamos a ver otro uso de esta clase que va a ser muy común, que va a ser a la hora de cargar
imágenes en nuestros juegos.
Si hacemos print(imagen_manzana)
P á g i n a 121 | 145
Un resumen de código:
import pygame
# Incializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
imagen_manzana =
pygame.image.load("baldosa_manzana.png").convert_alpha()
# Datos
manzana_rect = imagen_manzana.get_rect()
manzana_rect.x = 600
manzana_rect.y = 400
reloj = pygame.time.Clock()
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
# Evento
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
# Actualizar
ventana.blit(imagen_manzana, manzana_rect)
pygame.display.update()
# Salir
pygame.quit()
P á g i n a 122 | 145
Este será el resultado:
manzana_rect.x += 1
manzana_rect.y += 1
En las coordenadas:
manzana_rect.x = 100
manzana_rect.y = 100
P á g i n a 123 | 145
26.- Habitaciones
Vamos a llevar a cabo un juego sencillo en el que triplemente hay un personaje que se puede
mover por la ventana del juego en la que hemos puesto unos árboles, unas manzanas, un muro
y una puerta para poder acceder a otra habitación.
Es un juego sencillo pero nos va a permitir recapitular un poco el uso de las superficies y de los
rectángulos al mismo tiempo que vamos a poder ver algunas optimizaciones que pueden hacer
el juego más fluido.
P á g i n a 124 | 145
import pygame
import copy
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
VERDE = (0, 255, 0)
MARRON = (77, 38, 0)
AZUL = (0, 0, 255)
GRIS = (184, 184, 184)
# Mapa
mapa1 = [
" F ",
" F F ",
" AFAAF ",
" AAAFA MM ",
" F MM F",
" MM ",
" MM ",
" F P ",
" F "
] Vamos a definir dos mapas, cada uno
corresponde a una habitación.
mapa2 = [ mapa1 y mapa2.
" P F " ,
" AAFA ",
" F FAAA ",
" AFAA ",
" F ",
"F SSSS ",
" SSSS F ",
" F F "
]
P á g i n a 125 | 145
# Funciones
def construir_mapa(superficie, mapa):
limites = []
frutas = [] A continuación tenemos la función construir_mapa, que
puertas = [] nos va a retornar tres listas:
x = 0 Limites, frutas y puertas.
y = 0 En limites vamos guardar aquellas baldosas
for linea in mapa: que representan limites a los movimientos
for baldosa in linea: del jugador.
if baldosa == "M":
limites.append([baldosa_muro, baldosa_muro,
pygame.Rect(x,y, 80, 80)]) baldosa_agua y
baldosa_arbol.
elif baldosa == "S":
limites.append([baldosa_agua, M, S y A.
pygame.Rect(x,y, 80, 80)]) baldosa_manzana
elif baldosa == "A": F
limites.append([baldosa_arbol,
baldosa_puerta
pygame.Rect(x,y, 80, 80)])
P
elif baldosa == "F":
frutas.append([baldosa_manzana,
pygame.Rect(x, y, 80, 80)])
elif baldosa == "P":
puertas.append([baldosa_puerta,
pygame.Rect(x, y, 80, 80)])
x += 80
x = 0
y += 80
return limites, frutas, puertas
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
Cargamos la imágenes fondo
imagen_fondo =
pygame.image.load("img/fondo_mapa.png").convert()
Cargamos la imágenes baldosas
baldosa_muro =
pygame.image.load("img/baldosa_muro.png").convert()
baldosa_agua =
pygame.image.load("img/baldosa_agua.png").convert()
P á g i n a 126 | 145
Cargamos la imágenes baldosas
baldosa_arbol =
pygame.image.load("img/baldosa_arbol.png").convert_alph
a()
baldosa_puerta =
pygame.image.load("img/baldosa_puerta.png").convert_alp
ha()
baldosa_manzana =
pygame.image.load("img/baldosa_manzana.png").convert_al
pha()
Cargamos la imágenes del jugador
jugador0_par =
pygame.image.load("img/par_0.png").convert_alpha()
jugador1_der =
pygame.image.load("img/der_1.png").convert_alpha()
jugador2_der =
pygame.image.load("img/der_2.png").convert_alpha()
jugador3_der =
pygame.image.load("img/der_3.png").convert_alpha()
jugador4_der =
pygame.image.load("img/der_4.png").convert_alpha()
jugador1_izq =
pygame.image.load("img/izq_1.png").convert_alpha()
jugador2_izq =
pygame.image.load("img/izq_2.png").convert_alpha()
jugador3_izq =
pygame.image.load("img/izq_3.png").convert_alpha()
jugador4_izq =
pygame.image.load("img/izq_4.png").convert_alpha()
jugador1_arr =
pygame.image.load("img/arr_1.png").convert_alpha()
jugador2_arr =
pygame.image.load("img/arr_2.png").convert_alpha()
jugador3_arr =
pygame.image.load("img/arr_3.png").convert_alpha()
jugador4_arr =
pygame.image.load("img/arr_4.png").convert_alpha()
jugador1_abj =
pygame.image.load("img/baj_1.png").convert_alpha()
jugador2_abj =
pygame.image.load("img/baj_2.png").convert_alpha()
jugador3_abj =
pygame.image.load("img/baj_3.png").convert_alpha()
P á g i n a 127 | 145
Llama a una función que retorna tres
valores, por ese motivo son tuplas.
Cargamos la imágenes del jugador
jugador4_abj =
pygame.image.load("img/baj_4.png").convert_alpha()
jugador_rectangulo = jugador_imagen.get_rect()
jugador_rectangulo.x = 100 El jugador_rectangulo lo vamos a obtener de
jugador_rectangulo.y = 300 jugador_imagen con la que llamamos al
jugador_vel_x = 0 método get_rect().
jugador_vel_y = 0
La imagen jugador la hemos cargado y por lo
frames_jugador = 0
tanto es un objeto de la clase superficie y
vamos a obtener un objeto de la clase Rect.
# Bucle principal
jugando = True Le asignamos las coordenadas x e y, donde
queremos que aparezca el personaje al
while jugando:
comienzo del juego.
reloj.tick(60)
Definimos a 0 velocidad y frames del jugador.
# Eventos
for event in pygame.event.get(): En el bucle principal, como evento
if event.type == pygame.QUIT: somo vamos a definir el de cerrar
jugando = False ventana.
if moviendose_derecha:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
moviéndose_derecha las
jugador_imagen = jugador1_der
imágenes del jugador
elif frames_jugador < 11: serán:
jugador_imagen = jugador2_der
elif frames_jugador < 16:
jugador_imagen = jugador3_der
elif frames_jugador < 21:
jugador_imagen = jugador4_der
ventana.blit(jugador_imagen,
jugador_rectangulo)
elif moviendose_izquierda:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_izq moviéndose_izquierda las
elif frames_jugador < 11: imágenes del jugador
serán:
jugador_imagen = jugador2_izq
elif frames_jugador < 16:
jugador_imagen = jugador3_izq
elif frames_jugador < 21:
jugador_imagen = jugador4_izq
ventana.blit(jugador_imagen,
jugador_rectangulo)
P á g i n a 130 | 145
elif moviendose_arriba:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_arr
elif frames_jugador < 11:
jugador_imagen = jugador2_arr moviéndose_arriba las
elif frames_jugador < 16: imágenes del jugador
jugador_imagen = jugador3_arr serán:
elif frames_jugador < 21:
jugador_imagen = jugador4_arr
ventana.blit(jugador_imagen,
jugador_rectangulo)
elif moviendose_abajo:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_abj moviéndose_abajo las
elif frames_jugador < 11: imágenes del jugador
jugador_imagen = jugador2_abj serán:
elif frames_jugador < 16:
jugador_imagen = jugador3_abj
elif frames_jugador < 21:
jugador_imagen = jugador4_abj
ventana.blit(jugador_imagen,
jugador_rectangulo)
else:
jugador_imagen = jugador0_par Si no mostramos la
ventana.blit(jugador_imagen, imagen del jugador
jugador_rectangulo) parado.
# Actualizar
pygame.display.update()
# Salir
pygame.quit()
P á g i n a 131 | 145
Todas las imágenes necesarias para este proyecto:
P á g i n a 132 | 145
27.- Persecuciones
Un juego de plataformas o de acción sin otro personajes además del jugador no tendrían mucha
gracia, así que haremos otro personaje un monstruo, una versión simple que hemos estado
viendo en videos anteriores.
Podríamos hacer que se moviese de un lado al otro o cubriendo el paso a un camino, pero vamos
a ver otra posibilidad que podemos llevar a cabo.
Que si nos acercamos mucho a este monstruo, pues cuando entremos en su campo de visión el
monstruo persiga al personaje.
Vamos a partir en este capitulo que el monstruo está parado, nos iremos acercando poco a poco
cuando estamos cerca el monstruo nos empieza a seguir, cuando nos alejamos nos deja de
seguir.
P á g i n a 133 | 145
Como podemos implementar que el monstruo sea capaz de seguir al personaje, que una vez
visto le persiga mientras se mantenga a una distancia indicada.
Para ello lo que vamos a utilizar la formula la distancia entre dos puntos A y B.
La distancia entre dos puntos A y B sería el valor absoluto de la coordenada x punto B menos la
coordenada x del punto A elevado al cuadrado más la coordenada y menos la coordenada A
elevado al cuadrado y del resultado hacemos la raíz cuadrada.
Esta formula es una consecuencia del teorema de Pitágoras, el teorema de Pitágoras dice que
la hipotenusa al cuadrado es igual a la suma de los catetos al cuadrado. Por lo tanto A al
cuadrado más B al cuadrado es igual a C al cuadrado.
Despejamos el cuadrado de la C, la C será igual a la raíz cuadrada del cateto al cuadrado + cateto
al cuadrado.
P á g i n a 134 | 145
Si queremos calcular la distancia entre el punto A con las coordenadas (2,6) y el punto B con las
coordenadas (4,3) el vector D será igual a la formula que se muestra en la figura anterior.
P á g i n a 135 | 145
Para que el monstruo no salga de la ventana.
P á g i n a 136 | 145
P á g i n a 137 | 145
Te adjunto el código completo:
import pygame
import copy
import math
# Inicializar
pygame.init()
# Medidas
ANCHO = 1280
ALTO = 720
# Colores
BLANCO = (255, 255, 255)
NEGRO = (0, 0, 0)
VERDE = (0, 255, 0)
MARRON = (77, 38, 0)
AZUL = (0, 0, 255)
GRIS = (184, 184, 184)
# Mapa
mapa1 = [
" F ",
" F F ",
" AFAAF ",
" AAAFA MM ",
" F MM F",
" MM ",
" MM ",
" F P ",
" F "
]
mapa2 = [
" P F " ,
" AAFA ",
" F FAAA ",
" AFAA ",
" F ",
"F SSSS ",
" SSSS F ",
" F F "
]
# Funciones
def avistamiento(a,b,distancia):
if (math.sqrt(((b.x - a.x)**2) + ((b.y - a.y)**2))) < distancia:
return True
P á g i n a 138 | 145
else:
return False
# Ventana
ventana = pygame.display.set_mode((ANCHO, ALTO))
reloj = pygame.time.Clock()
imagen_fondo = pygame.image.load("img/fondo_mapa.png").convert()
baldosa_muro = pygame.image.load("img/baldosa_muro.png").convert()
baldosa_agua = pygame.image.load("img/baldosa_agua.png").convert()
baldosa_arbol =
pygame.image.load("img/baldosa_arbol.png").convert_alpha()
baldosa_puerta =
pygame.image.load("img/baldosa_puerta.png").convert_alpha()
baldosa_manzana =
pygame.image.load("img/baldosa_manzana.png").convert_alpha()
monstruo1_der = pygame.image.load("img1/mon_der1.png").convert_alpha()
monstruo2_der = pygame.image.load("img1/mon_der2.png").convert_alpha()
monstruo1_izq = pygame.image.load("img1/mon_izq1.png").convert_alpha()
monstruo2_izq = pygame.image.load("img1/mon_izq2.png").convert_alpha()
monstruo1_arr = pygame.image.load("img1/mon_arr1.png").convert_alpha()
monstruo2_arr = pygame.image.load("img1/mon_arr2.png").convert_alpha()
P á g i n a 139 | 145
monstruo1_baj = pygame.image.load("img1/mon_baj1.png").convert_alpha()
monstruo2_baj = pygame.image.load("img1/mon_baj2.png").convert_alpha()
monstruo0_par = pygame.image.load("img1/mon_par0.png").convert_alpha()
monstruo_imagen = monstruo0_par
jugador0_par = pygame.image.load("img/par_0.png").convert_alpha()
jugador1_der = pygame.image.load("img/der_1.png").convert_alpha()
jugador2_der = pygame.image.load("img/der_2.png").convert_alpha()
jugador3_der = pygame.image.load("img/der_3.png").convert_alpha()
jugador4_der = pygame.image.load("img/der_4.png").convert_alpha()
jugador1_izq = pygame.image.load("img/izq_1.png").convert_alpha()
jugador2_izq = pygame.image.load("img/izq_2.png").convert_alpha()
jugador3_izq = pygame.image.load("img/izq_3.png").convert_alpha()
jugador4_izq = pygame.image.load("img/izq_4.png").convert_alpha()
jugador1_arr = pygame.image.load("img/arr_1.png").convert_alpha()
jugador2_arr = pygame.image.load("img/arr_2.png").convert_alpha()
jugador3_arr = pygame.image.load("img/arr_3.png").convert_alpha()
jugador4_arr = pygame.image.load("img/arr_4.png").convert_alpha()
jugador1_abj = pygame.image.load("img/baj_1.png").convert_alpha()
jugador2_abj = pygame.image.load("img/baj_2.png").convert_alpha()
jugador3_abj = pygame.image.load("img/baj_3.png").convert_alpha()
jugador4_abj = pygame.image.load("img/baj_4.png").convert_alpha()
jugador_imagen = jugador0_par
# Datos
habitacion1 = construir_mapa(ventana, mapa1)
habitacion2 = construir_mapa(ventana, mapa2)
habitacion = habitacion1
jugador_rectangulo = jugador_imagen.get_rect()
jugador_rectangulo.x = 100
jugador_rectangulo.y = 300
jugador_vel_x = 0
jugador_vel_y = 0
frames_jugador = 0
monstruo_rectangulo = monstruo_imagen.get_rect()
monstruo_rectangulo.x = 600
monstruo_rectangulo.y = 300
frames_monstruo = 0
# Bucle principal
jugando = True
while jugando:
reloj.tick(60)
P á g i n a 140 | 145
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
jugando = False
moviendose_derecha = False
moviendose_izquierda = False
moviendose_arriba = False
moviendose_abajo = False
jugador_vel_x = 0
jugador_vel_y = 0
pulsado = pygame.key.get_pressed()
if pulsado[pygame.K_LEFT]:
jugador_vel_x = -3
moviendose_izquierda = True
if pulsado[pygame.K_RIGHT]:
jugador_vel_x = 3
moviendose_derecha = True
if pulsado[pygame.K_UP]:
jugador_vel_y = -3
moviendose_arriba = True
if pulsado[pygame.K_DOWN]:
jugador_vel_y = 3
moviendose_abajo = True
# Lógica monstruo
monstruo_derecha = False
monstruo_izquierda = False
monstruo_abajo = False
monstruo_arriba = False
monstruo_parado = False
# Colisiones
if monstruo_rectangulo.collidepoint(jugador_rectangulo.centerx,
jugador_rectangulo.centery):
pygame.time.delay(1000)
break
# Lógica
jugador_rectangulo.x += jugador_vel_x
jugador_rectangulo.y += jugador_vel_y
ventana.blit(imagen_fondo, (0,0))
# Movimientos mostruo
if monstruo_derecha:
frames_monstruo += 1
if frames_monstruo >= 21:
frames_monstruo = 1
if frames_monstruo < 11:
monstruo_imagen = monstruo1_der
elif frames_monstruo < 21:
monstruo_imagen = monstruo2_der
ventana.blit(monstruo_imagen, monstruo_rectangulo)
elif monstruo_izquierda:
frames_monstruo += 1
if frames_monstruo >= 21:
frames_monstruo = 1
if frames_monstruo < 11:
monstruo_imagen = monstruo1_izq
elif frames_monstruo < 21:
monstruo_imagen = monstruo2_izq
ventana.blit(monstruo_imagen, monstruo_rectangulo)
elif monstruo_abajo:
frames_monstruo += 1
if frames_monstruo >= 21:
frames_monstruo = 1
if frames_monstruo < 11:
monstruo_imagen = monstruo1_baj
elif frames_monstruo < 21:
monstruo_imagen = monstruo2_baj
ventana.blit(monstruo_imagen, monstruo_rectangulo)
elif monstruo_arriba:
frames_monstruo += 1
if frames_monstruo >= 21:
frames_monstruo = 1
if frames_monstruo < 11:
P á g i n a 143 | 145
monstruo_imagen = monstruo1_arr
elif frames_monstruo < 21:
monstruo_imagen = monstruo2_arr
ventana.blit(monstruo_imagen, monstruo_rectangulo)
ventana.blit(jugador_imagen, jugador_rectangulo)
elif moviendose_izquierda:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_izq
elif frames_jugador < 11:
jugador_imagen = jugador2_izq
elif frames_jugador < 16:
jugador_imagen = jugador3_izq
elif frames_jugador < 21:
jugador_imagen = jugador4_izq
ventana.blit(jugador_imagen, jugador_rectangulo)
elif moviendose_arriba:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_arr
elif frames_jugador < 11:
jugador_imagen = jugador2_arr
elif frames_jugador < 16:
jugador_imagen = jugador3_arr
elif frames_jugador < 21:
jugador_imagen = jugador4_arr
P á g i n a 144 | 145
ventana.blit(jugador_imagen, jugador_rectangulo)
elif moviendose_abajo:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_abj
elif frames_jugador < 11:
jugador_imagen = jugador2_abj
elif frames_jugador < 16:
jugador_imagen = jugador3_abj
elif frames_jugador < 21:
jugador_imagen = jugador4_abj
ventana.blit(jugador_imagen, jugador_rectangulo)
else:
jugador_imagen = jugador0_par
ventana.blit(jugador_imagen, jugador_rectangulo)
# Actualizar
pygame.display.update()
# Salir
pygame.quit()
P á g i n a 145 | 145