0% encontró este documento útil (0 votos)
23 vistas146 páginas

Pygame

El documento es un tutorial sobre cómo crear juegos utilizando la librería Pygame en Python. Incluye instrucciones sobre la instalación de Pygame, la creación de una ventana, manejo de eventos, y dibujo de figuras, así como el movimiento de objetos en la pantalla. Se presenta de manera estructurada, con secciones que abordan diferentes aspectos del desarrollo de juegos, desde lo básico hasta técnicas más avanzadas.

Cargado por

diplexstudios
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
23 vistas146 páginas

Pygame

El documento es un tutorial sobre cómo crear juegos utilizando la librería Pygame en Python. Incluye instrucciones sobre la instalación de Pygame, la creación de una ventana, manejo de eventos, y dibujo de figuras, así como el movimiento de objetos en la pantalla. Se presenta de manera estructurada, con secciones que abordan diferentes aspectos del desarrollo de juegos, desde lo básico hasta técnicas más avanzadas.

Cargado por

diplexstudios
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 146

Para seguir los videotutoriales en YouTube

en el canal de Manuel González llamado


Programar es como un juego.

PYGAME EN PYTHON
¿CÓMO CREAR JUEGOS?

PERE MANEL VERDUGO ZAMORA


[email protected]
Contenido
1.- Instalando pygame ................................................................................................................... 2
2.- Primera ventana en pygame .................................................................................................... 7
3.- Eventos de pygame ................................................................................................................ 10
4.- Pantalla completa en pygame ................................................................................................ 15
5.- Coordenadas de pygame ....................................................................................................... 17
6.- Dibujando con pygame .......................................................................................................... 20
7.- Movimiento en pygame ......................................................................................................... 23
8.- Más movimiento de figuras ................................................................................................... 30
9.- Poniendo texto en pygame .................................................................................................... 32
10.- Añadiendo puntuación......................................................................................................... 35
11.- Cuadros (frames) por segundo ............................................................................................ 37
12.- Moviendo personajes en pygame ........................................................................................ 48
13.- Cambiando orientación de las figuras.................................................................................. 53
14.- Animación de figuras en pygame ......................................................................................... 57
15.- Colisiones en pygame........................................................................................................... 61
16.- Cargando imágenes.............................................................................................................. 67
17.- Usar método convert con las imágenes en pygame ............................................................ 74
18.- Añadiendo figuras ................................................................................................................ 77
19.- Poniendo niveles .................................................................................................................. 82
20.- Clase Rect en pygame .......................................................................................................... 94
21.- Método colliderect de la clase Rect. .................................................................................... 99
22.- Muros con pygame ............................................................................................................ 101
23.- Mapas con pygame ............................................................................................................ 106
24.- Método collidepoint .......................................................................................................... 115
25.- La clase Surface de pygame ............................................................................................... 119
26.- Habitaciones....................................................................................................................... 124
27.- Resecuciones ...................................................................................................................... 132

P á g i n a 1 | 145
1.- Instalando pygame

Modo texto → Consola del sistema


Consola del IDLE

Modo gráfico → Interface gráfica (GUI)


Empezamos un nuevo tutorial en que vamos a intentar hacer nuestros primeros juegos en modo
gráfico.

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.

Librerías orientadas a aplicaciones de escritorio:

Tkinter, wxPython, PyQt, Pyside, PyGTK, …

Librerías orientadas a juegos:

Pygame, Pyglet, Arcade, …

Nosotros vamos a utilizar Pygame.

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.

Vamos a abrir Cmd del sistema:

P á g i n a 2 | 145
Lo primero que vamos a comprobar si tenemos definidas las variables del entorno del sistema
para Python.

Vamos a escribir python.

Tenemos que entrar en el intérprete de Python.

Para salir escribiremos exit()

P á g i n a 3 | 145
Vamos a ver si tenemos definidas las variables para el entorno pip.

Muestra una información general de este comando.

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.

Vamos a realizar un pip list para ver si ya lo tenemos.

Ya lo tenemos.

P á g i n a 5 | 145
Vamos al intérprete de Python y escribimos import pygame.

Hemos instalado correctamente esta librería y vamos a poder utilizarla.

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/

Hay muchos tutoriales, pero están en inglés.

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

Desde la cmd de Windows:

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.

Al ejecutar la ventana a aparecido pero de inmediato se ha cerrado, para mantener la ventana.

La ventana se muestra durante 3 segundos.

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.

Lo primero que hacíamos era importar la librería pyame.

Posteriormente inicializábamos con la función init los módulos de esta librería.

Ya estamos en condiciones de crear nuestra primera ventana.

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.

Otra forma de definir el color es creando constates:

Para luego asignárselo al método fill.

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.

Tenemos que actualizar la ventana.

Fuera del bucle para que se cierre la ventana.

Vamos a ejecutar:

Se ejecuta la ventana pero al intentar cerrarla se reproduce un error.

Código completo:

import pygame

pygame.init()

ANCHO = 800
ALTO = 600
BLANCO = (255,255,255)
NEGRO = (0, 0, 0)
ROJO = (255, 0, 0)

ventana = pygame.display.set_mode((ANCHO, ALTO))

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.

En la línea 14 definimos una variable con el valor True.

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 18 estamos comparando si el evento es que hemos presionado la x de la ventana para


cerrarla.

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.

En la línea 20 queremos comparar si el evento es referente a presionar una tecla.

En la línea 21 comparamos si hemos presionado la tecla ‘q’ si es así en la línea 22 volvemos a


asignar a la variable False para que finalice el bucle while.

Ya podemos cerrar dándole a la x.

También presionando la tecla ‘q’.

Te adjunto el código completo:

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.

Puede ir todo en la misma línea.


Antes de ejecutar, tenemos que saber las medidas de resolución de tu ordenador.
Botón derecho del ratón sobre el escritorio y seleccionaremos configuración de pantalla.

Y vemos la resolución en mi caso es de 1920 x 1080.

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)

Este será el resultado:

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.

De otro modo si tuviéramos ciento de figuras o imágenes el juego no se vería adecuadamente,


así cuando ya está todo en memoria mediante la función update() se plasma todo en la ventana.

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.

Por lo tanto primero rellenamos el fondo y luego el cuadrado.

Te propongo este ejercicio:

P á g i n a 19 | 145
6.- Dibujando con pygame
La solución:

La primera coordenada es la parte superior izquierda del cuadrado y la segunda coordenada en


con respecto a la primera.

(10,10)

(100,100)

Con relación al punto


inicial.

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.

Vamos a eliminar los todos los cuadrados para dibujar un círculo.

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.

Vamos a dibujar una línea.

Sus parámetros son donde la dibujamos (ventana), el color, Coordenada_Inicial ,


Coordenada_final.

Vamos a dibujar figuras poligonales.

Como la siguiente figura:

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:

Vamos a ver un cuadrado de color verde en un fondo negro.

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.

Que pasa si en cada iteración no volvemos a pintar el fondo de la pantalla:

Se iría pintando el cuadrado pero dejando rastro.


Como queremos que el cuadrado no se salga de la ventana vamos a realizar lo siguiente:

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:

Para mi este será el resultado:

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

fuente = pygame.font.SysFont("segoe print", 30)


texto = fuente.render("CUADRADOS", True, BLANCO)

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

Este será el resultado:

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.

Vamos a cambiar las coordenadas.

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

fuente1 = pygame.font.SysFont("arial black", 32)


fuente2 = pygame.font.SysFont("consolas", 24)

texto1 = fuente1.render("CUADRADOS", True, BLANCO)


puntos = 0
Creamos dos variables para el
vueltas = 0
recuento de puntos y vueltas.

# 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

texto_puntos = fuente2.render("Puntos: " +


str(puntos), True, BLANCO)
texto_vueltas = fuente2.render("Vueltas: " +
str(vueltas), True, BLANCO)

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

# Salir El marco texto_puntos lo colocamos


pygame.quit() en las coordenada (30, 30).

El marco texto_vueltas lo colocamos


en lsa coordenadas (640, 20)

Este será el resultado:

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.

Podrás observar que se


mueven muy rápido, si
quisiéramos simular
unos asteroides.

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.

De esta forma después de cada actualización de la pantalla el tiempo se pausa durante 10


milisegundos antes de volverse a actualizar la pantalla.

Vamos a ver otro forma de llevar esta tarea que además va a poder repercutir en otro aspectos
de los juegos.

Eliminamos la línea 54.

Creamos un objeto de tipo reloj.

El objeto de tipo reloj con la porpiedad tick puede medir el tiempo.

Creamos una variable llamada frames de tipo int asignándole el valor de 0.

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.

Esta información no es muy útil.

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)

reloj = pygame.time.Clock() Creamos un objeto de tipo reloj, la


clase time tiene un método
llamado Clock() que nos va a
# Datos permitir medir el tiempo que
cuadrados = [] transcurre entre una actualización
for i in range(50): a otra.
x = random.randint(1, 799)
y = random.randint(1, 599)
c = [x, y]
c = cuadrados.append(c) Creamos las siguientes variables.
frames = 0
Transcurrido será el tiempo
transcurrido = 0
trancurrido. fps los cuadros por
fps = 0 segundo
segundos = 0

Con esta condición controlamos que


# Bucle principal
si transcurrido es mayor o igual a
jugando = True 1000, es decir han transcurrido 1
while jugando: segundo, la variable fps asumirá el
if transcurrido >= 1000: valor frames, frames pasará a valer 0,
fps = frames se incrementa segundos en 1 y la
frames = 0 variable transcurrido pasa a valer 0.
segundos += 1
transcurrido = 0

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

texto1 = fuente.render(str(fps), True, BLANCO)


texto2 = fuente.render(str(segundos), True, BLANCO)
ventana.blit(texto1, (80,100))
ventana.blit(texto2, (600, 100))

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

Cuadros por segundo – Se mide en FPS – Depende de la CPU o GPU (Frames)

Frecuencia de refresco – Se mide en HZ – Depende del monitor

Si el monitor es de 60 Hz se refrescará 60 veces por segundo, mostrando 60 imágenes nuevas


por segundo.

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.

Cambiamos a 500 cuadrados.

Ya han bajado de 700 cuando mi CPU con 50 iba a 1400.

Si ponemos 5000 irá a unos 230.

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

Dentro de modulo time tenemos la función pygame.time.get_ticks() que


nos devuelve el tiempo en milisegundos.

Dentro de la clase pygame.time.Clock tenemos el método get_fps() que


nos devuelve los fps directamente sin tener que calcularlos.

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.

Recogemos la plantilla de videos anteriores y realizamos las siguientes modificaciones:

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.

Dibujamos los dos cuadrados con sus


# Dibujos respectivas coordenadas y dimensiones.
ventana.fill(NEGRO)

pygame.draw.rect(ventana, NARANJA, (aste_pos_x,


aste_pos_y, 60, 60))
pygame.draw.rect(ventana, VERDE, (nave_pos_x,
nave_pos_y, 60, 60))

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

Para ello vamos a realizar algunas modificaciones.

Vamos a simular las leyes de la física del movimiento.

E = V x T → Espacio es igual a Velocidad por Tiempo.

O Espacio_Final es igual Espacio_Inicial más la Velocidad por el Tiempo

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.

# Dibujos Los valores de las variable aste_pos_x y


ventana.fill(NEGRO) aste_pos_y las controla el programa.

pygame.draw.rect(ventana, NARANJA, (aste_pos_x,


aste_pos_y, 60, 60))
pygame.draw.rect(ventana, VERDE, (nave_pos_x,
nave_pos_y, 60, 60))

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

def nave_abajo(superficie, x ,y):


pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x, y+30, 15,
30))
pygame.draw.rect(superficie, NEGRO, (x + 45, y+30,
15, 30))

def nave_derecha(superficie, x ,y):


pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x+30, y, 30,
15))
pygame.draw.rect(superficie, NEGRO, (x+30, y+45,
30, 15))

def nave_izquierda(superficie, x, y):


pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x, y, 30, 15))

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)

pygame.draw.rect(ventana, NARANJA, (aste_pos_x,


aste_pos_y, 60, 60))
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)

Según el valor que asuma dirección, esta


# Update llamará a la correspondiente función.
pygame.display.update()
nave_arriba(), nave_abajo(),
nave_derecha() o nave_izquierda()
pygame.quit()
P á g i n a 55 | 145
P á g i n a 56 | 145
14.- Animación de figuras en pygame
Continuando con el proyecto anterior vamos a hacer que nuestro asteroide vaya rotando.

Este será el código final:

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

def nave_abajo(superficie, x ,y):


pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x, y+30, 15,
30))
pygame.draw.rect(superficie, NEGRO, (x + 45, y+30,
15, 30))

def nave_derecha(superficie, x ,y):


pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
pygame.draw.rect(superficie, NEGRO, (x+30, y, 30,
15))
pygame.draw.rect(superficie, NEGRO, (x+30, y+45,
30, 15))

def nave_izquierda(superficie, x, y):


pygame.draw.rect(superficie, VERDE, (x, y, 60, 60))
P á g i n a 57 | 145
pygame.draw.rect(superficie, NEGRO, (x, y, 30, 15))
pygame.draw.rect(superficie, NEGRO, (x, y+45, 30,
15))

def asteroide_1(superficie, x, y):


pygame.draw.rect(superficie, NARANJA, (x, y, 60,
60))
pygame.draw.rect(superficie, NEGRO, (x, y, 20, 20))

def asteroide_2(superficie, x, y):


pygame.draw.rect(superficie, NARANJA, (x, y, 60,
60))
pygame.draw.rect(superficie, NEGRO, (x+40, y, 20,
20))

def asteroide_3(superficie, x, y):


pygame.draw.rect(superficie, NARANJA, (x, y, 60,
60))
pygame.draw.rect(superficie, NEGRO, (x+40, y+40,
20, 20))

def asteroide_4(superficie, x, y):


pygame.draw.rect(superficie, NARANJA, (x, y, 60,
60))
pygame.draw.rect(superficie, NEGRO, (x, y+40, 20,
20))

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

contador = 0 Según el valor de al variable contador el


asteroide tendrá un determinado giro.
# 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"
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.

Si contador mayor o igual a 41


# Dibujos lo volvemos a reiniciar a 0.
ventana.fill(NEGRO)

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.

Vamos a trabajar sobre este código:

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

def asteroide(superficie, x, y, ancho, alto):


pygame.draw.rect(superficie, NARANJA, (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()

Vamos a realizar las siguientes modificaciones:

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

<

Las líneas 84 y 85 hacer que el asteroide retorne a un punto de partida.

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.

Partiendo del siguiente código:

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)

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

Este será el resultado:

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.

Vamos a buscar los archivos con los dibujos.

En este primer ejemplo lo vamos a dibujar con el Paint de Windows.

P á g i n a 68 | 145
Vamos a cambiar las dimensiones que tienen que coincidir con las dimensiones de la ventana.

Realizaremos el siguiente dibujo.


Ahora lo vamos a guardar con el formato PNG que para los juegos es el más recomendado.
Vamos a realizar el asteroide de 64 x 64 pixeles.

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.

Ya tenemos los dos asteroides.

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)

ventana = pygame.display.set_mode((ANCHO, ALTO))


reloj = pygame.time.Clock()

# 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.draw.rect(ventana, NARANJA, (200, 200, 60,


60))
pygame.draw.rect(ventana, VERDE, (600, 500, 60,
60))
pygame.display.update()

pygame.quit()

Este será el resultado:

Ahora temenos que instertar los meteoritos.

Vamos a diseñar la nave:

P á g i n a 71 | 145
Vamos a eliminar los dos cuadrados.

Este serán las modificaciones:

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)

ventana = pygame.display.set_mode((ANCHO, ALTO))


reloj = pygame.time.Clock()

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

# Bucle principal Con la variable fondo cargamos en memoria el archivo fondo.png.


jugando = True Con la variable asteroide_A1 cargamos la imagen asteroidea_1.png.
Si las imágenes se han realizado con el Paint con la sentencia
while jugando:
set_color.key le dedimos que color queremos eliminar.

reloj.tick(60) Con la variable asteroide_A2 cargamos la imagen ateroideB_1.png y


por último con la variable nave_arriba cargamos nave_arriba.png.
# Eventos

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.

Este será el resultado:

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.

El resultado se muestra en la imagen anterior.

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.

Las transparencias las convierte en color negro.

Este será el resultado:

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

# Medidas Cuando llamemos a esta función con los


ANCHO = 1280 parámetros (Ancho, Alto del arteroide,
ALTO = 720 Ancho y alto de la nave, posición x y
posición y de la nave, tamaño x e y de la
nave, cuando choca la profundidad del
# Colores choque.
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

ventana = pygame.display.set_mode((ANCHO, ALTO))


reloj = pygame.time.Clock()
fuente = pygame.font.SysFont("arial black", 20)

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

aste_1 = [aste_1a, aste_1b, aste_1c, aste_1d]


aste_3 = [aste_1b, aste_1c, aste_1d, aste_1a]
aste_4 = [aste_1c, aste_1d, aste_1a, aste_1b]
aste_5 = [aste_1d, aste_1a, aste_1b, aste_1c]

asteroides_grandes = [] Cada asteroide realizará la rotación


independiente.
for i in range(10):
x = random.randint(0, ANCHO) Lista vacía
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)
En el ciclo for se almacenan
# Datos ancho, alto, velocidad posición
de rotación del asteroide con
vidas = 3 valores aleatorios que al final se
almacenan en la lista
nivel = 1
aterorides_grandes.

nave_pos_x = 600 Un total de 10 asteroides.


nave_pos_y = 670
nave_vel_x = 0 Posición de la nave, con coordenadas x e y.
nave_vel_y = 0 Velocidad en x como en y a 0.
direccion = "arriba"
Dirección mirando hacia arriba.
frames_asteroides = 0
Frames = 0 (controlará la rotación del asteroide.
# Bucle principal
P á g i n a 78 | 145
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 = 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

Cuando presionamos las teclas de dirección, las variables P á g i n a 79 | 145


nave_vel_x y nave_vel_y cambian sus valores.
if nave_pos_x > ANCHO - 32:
Impide que la nave por la
nave_pos_x = ANCHO - 32 derecha, izquierda y abajo
if nave_pos_x < 0: salga de la ventana.
nave_pos_x = 0
if nave_pos_y > ALTO -32:
nave_pos_y = ALTO - 32
Controla si la nave toca a
if nave_pos_y < 10: algún asteroide.
jugando = False

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

if frames_asteroides < 11:


for a in asteroides_grandes:
ventana.blit(a[0][0], (a[1], a[2]))
elif frames_asteroides < 21:
for a in asteroides_grandes:
ventana.blit(a[0][1], (a[1], a[2]))
elif frames_asteroides < 31:
for a in asteroides_grandes:
ventana.blit(a[0][2], (a[1], a[2]))
elif frames_asteroides < 41:
for a in asteroides_grandes:
ventana.blit(a[0][3], (a[1], a[2]))

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.

Cuando ejecutamos el programa nos aparece la pantalla de inicio

Pantalla final cuando pierdes.

Pantalla final habiendo ganado el 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.

A continuación vamos a crear un nuevo archivo llamado boceto_bucle.py y escribiremos el


siguiente código:

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:

# Evento Cerrar ventana:


# en_nivel = Falsa
# en_partida = False
# en_juego = False
# Eventos Moverse

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

Esta es la estructura donde tiene que ir el juego.

Ahora vamos a implementar los bucles al código del ejercicio anterior.

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_1 = [aste_1a, aste_1b, aste_1c, aste_1d]


aste_3 = [aste_1b, aste_1c, aste_1d, aste_1a]
aste_4 = [aste_1c, aste_1d, aste_1a, aste_1b]
aste_5 = [aste_1d, aste_1a, aste_1b, aste_1c]

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

aste_2 = [aste_2a, aste_2b, aste_2c, aste_2d]


P á g i n a 86 | 145
aste_6 = [aste_2b, aste_2c, aste_2d, aste_2a]
aste_7 = [aste_2c, aste_2d, aste_2a, aste_2b]
aste_8 = [aste_2d, aste_2a, aste_2b, aste_2c]

# Bucle principal

en_juego = True Variable en_juego de tipo booleana valor True


while en_juego: El bucle en_juego

num_vidas = 3 Inicializamos las variables num:_vidas a


num_nivel = 1 3 y num_nivel a 1

en_partida = False Inicializamos las variables en_partida


en_inicio = True a False u en_incio a True

while en_inicio: Bucle en_inicio Evento cerrar ventana

for event in pygame.event.get():


if event.type == pygame.QUIT:
en_inicio = False En_inicio igual a False
en_juego = False en_juego igual a False

if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
en_inicio = False
en_partida = True

ventana.fill(NEGRO) Evento entrar partida igual a


True.
historia = [
" MISIÓN A JUPITER",
" Tras meses de viaje en misión a
Júpiter ya sólo se",
" interponen en tu camino tres
cinturones de asteroides",
" que te dificultan el paso y amenazan con
no dejarte pasar.",
" Intenta traspasarlos para conseguir
finalizar tu misión.",
"",

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

while en_partida: Bucle en_partida Se crean los


asteroides.
en_final = False En_final igual a False

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

reloj.tick(60) Evento cerrar ventana

# 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

if nave_pos_x > ANCHO - 32:


nave_pos_x = ANCHO - 32
if nave_pos_x < 0:
nave_pos_x = 0
if nave_pos_y > ALTO - 32:
nave_pos_y = ALTO - 32

if nave_pos_y < 10:


en_nivel = False Llegar arriba
num_nivel += 1
Colisión

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

texto1 = fuente1.render("Nivel: " +


str(num_nivel), True, BLANCO)
texto2 = fuente1.render("Vidas: " +
str(num_vidas), True, BLANCO)
ventana.blit(texto1, (20,10))
ventana.blit(texto2, (1150, 10))

frames_asteroides += 1
if frames_asteroides >= 41:
frames_asteroides = 1

if frames_asteroides < 11:


for a in asteroides:
ventana.blit(a[0][0], (a[1], a[2]))
elif frames_asteroides < 21:
for a in asteroides:
ventana.blit(a[0][1], (a[1], a[2]))
elif frames_asteroides < 31:
for a in asteroides:
ventana.blit(a[0][2], (a[1], a[2]))
elif frames_asteroides < 41:
for a in asteroides:
ventana.blit(a[0][3], (a[1], a[2]))

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

while en_final: Bucle en_final Cerrar ventana

for event in pygame.event.get():


if event.type == pygame.QUIT:
en_final = False
en_partida = False No jugar
en_juego = False

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:

Vamos con otro ejemplo:

Vamos a agregar las siguientes líneas:

Este será el resultado:

En este caso los dos rectángulos han colisionado.

Partiendo de esta platilla:

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

if nave_pos_x > ANCHO - 50:


nave_pos_x = ANCHO - 50
P á g i n a 96 | 145
if nave_pos_x < 0:
nave_pos_x = 0
if nave_pos_y > ALTO - 50:
nave_pos_y = ALTO - 50
if nave_pos_y < 0:
nave_pos_y = 0

# Dibujos
ventana.fill(NEGRO)
pygame.draw.rect(ventana, AZUL,
(nave_pos_x,nave_pos_y, 50, 50))

# Actualizar
pygame.display.update()

# Salir
pygame.quit()

Ahora vamos a cambiarlo por la clase Rect.

En datos creamos el objeto nave, y los valores para el alto y ancho ya no son necesarios.

Al trabajar con una clase utilizamos el método del punto.

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.

Te propongo que realices el siguiente reto:

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.

Vamos a agregar el color VERDE.

En el apartado lógica controlamos la colisión.

Para hacer la simulación de un muero donde el personaje no puede traspasar el muro.

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:

Siguiendo con el proyecto anterior vamos a agregar las siguientes funciones:

Creamos los muros:

Ahor agregamos el personaje:

Elimina los objetos de nave y roca.

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.

Dibujamos los muros y el personaje.

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.

Para evitar estas separaciones vamos a realizar las siguientes modificaciones:

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.

Pero no controlamos cuando pulsamos simultáneamente dos teclas para ir en diagonal.

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)

def dibujar_personaje(superficie, rectangulo):


pygame.draw.rect(superficie, AZUL, 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

roca = pygame.Rect(500, 200, 300, 100)


nave = pygame.Rect(600, 500, 50, 50)
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:
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

if personaje.x > ANCHO - personaje.width:


personaje.x = ANCHO - personaje.width
if personaje.x < 0:
personaje.x = 0
if personaje.y > ALTO - personaje.height:
personaje.y = ALTO - personaje.height
if personaje.y < 0:
personaje.y = 0

for muro in muros:


if personaje.colliderect(muro):
personaje.x -= personaje_vel_x
personaje.y -= personaje_vel_y
# Dibujos
ventana.fill(NEGRO)

for muro in muros:


dibujar_muro(ventana, muro)

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.

Eliminamos la lista muros y vamos a crear un mapa.

Creamos el correspondiente mapa, para que sean las baldosas de la ventana del juego.

Como la ventana tiene unas medidas de 1280 x 720

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.

Nosotros vamos a trabajar 16 x 9 ya que el mapa en horizontal son 16 y en vertical son 9.

Vamos a definir una función:

P á g i n a 109 | 145
Vamos a crear otra función:

Llamamos a la función construir_mapa (con el argumento mapa).

Agregamos dibujar_mapa(ventana, muros).

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 dibujar_personaje(superficie, rectangulo):


pygame.draw.rect(superficie, AZUL, 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

def dibujar_mapa(superficie, muros): Esta función con los


for muro in muros: argumentos superficie y muro
dibujar_muro(superficie, muro) con un ciclo for dibuja las
baldosas.

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

# Datos Llamamos a la función construir_mapa para


que retorne una lista con las baldosas.
muros = construir_mapa(mapa)
personaje = pygame.Rect(80, 80, 50, 50)
personaje_vel_x = 0
personaje_vel_y = 0

roca = pygame.Rect(500, 200, 300, 100)


nave = pygame.Rect(600, 500, 50, 50)
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:
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

if personaje.x > ANCHO - personaje.width:


personaje.x = ANCHO - personaje.width
if personaje.x < 0:
personaje.x = 0
if personaje.y > ALTO - personaje.height:
personaje.y = ALTO - personaje.height
if personaje.y < 0:
personaje.y = 0

for muro in muros:


if personaje.colliderect(muro):
personaje.x -= personaje_vel_x
personaje.y -= personaje_vel_y
# Dibujos
Este bucle controla que nuestro personaje
ventana.fill(NEGRO)
no pueda traspasar el muro.

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.

for muro in muros: Un recorrido por todas las baldosas,


dibujar_muro(ventana, muro) llama a función dibujar_muro con los
parámetros ventana y muro (baldosa)
dibujar_personaje(ventana, personaje)

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

Vamos a escribir el siguiente código:

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 dibujar_manzana(superficie, rectangulo):


pygame.draw.rect(superficie, VERDE, rectangulo)

def dibujar_personaje(superficie, rectangulo):


P á g i n a 115 | 145
pygame.draw.rect(superficie, AZUL, 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.

def dibujar_mapa(superficie, muros, manzanas):


for muro in muros:
dibujar_muro(superficie, muro)
for manzana in manzanas:
dibujar_manzana(superficie, manzana)

# 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

for manzana in list(manzanas):


if personaje.collidepoint(manzana.centerx,
manzana.centery):
manzanas.remove(manzana)

# Dibujos La función dibujar_mapa ahora le


ventana.fill(CLARO) pasamos tres argumentos.

dibujar_mapa(ventana, muros, manzanas)


dibujar_personaje(ventana, personaje)
P á g i n a 117 | 145
# Actualizar
pygame.display.update()

# Salir
pygame.quit()

Nos vamos a comer las manzanas.

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

Esta función nos va a crear un objeto de tipo superficie.

Si hacemos un print(ventna) para que nos muestre que tipo de objeto es.

<Surface (1280x720x32 SW)>

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:

manzana = pygame.Surface((50, 50)), vamos a ver el contenido de esta variable.

print(manzana)

<Surface (50x50x32 WS)>

La superficie menor la podemos pegar a una superficie mayor, la manzana a la ventana.

ventana.blit(manzana, (600, 400))

Nos pega una superficie, pero por defecto tiene el color negro.

Podemos hacer los siguiente:

P á g i n a 119 | 145
manzana.fill(ROJO)

ventana.blit(manzana, (600, 400))

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

Vamos a hace un print(manzana_rect)

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

En la carpeta del proyecto tengo una baldosa manzana.

Si hacemos print(imagen_manzana)

<Surface (80x80x32 SW)>

Como las baldosas que hicimos en el capítulo del mapa.

Ya tenemos imagen_manzana y manzana_rect.

La ubicamos en las coordenadas x = 600 e y = 400.

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:

Podemos agregar el siguiente código para que la manzana se mueva:

manzana_rect.x += 1

manzana_rect.y += 1

En las coordenadas:

manzana_rect.x = 100

manzana_rect.y = 100

Cuando ejecutemos se moverá en diagonal.

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.

A continuación vamos a comentar el código de este proyecto.

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_imagen = jugador0_par A la variable jugador_imagen le


asignamos la del jugador parado.
# Datos
habitacion1 = construir_mapa(ventana, mapa1)
habitacion2 = construir_mapa(ventana, mapa2)

habitacion = habitacion1 Hemos creado dos habitaciones habitaccion1 y habitacion2.


La variable habitación le asignamos habitacion1

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.

Vamos a utilizar la función


moviendose_derecha = False get.pressed(), esta función lo que hace
moviendose_izquierda = False es ver el estado de cada una de las
moviendose_arriba = False teclas del teclado y devolver un valor
moviendose_abajo = False booleano.

Si pulsamos la tecla izquierda vamos


jugador_vel_x = 0 cambiar el valor de la variable
jugador_vel_y = 0 moviéndose_izquierda a True, además
de controlar la velocidad de jugador.
pulsado = pygame.key.get_pressed() Haremos lo mismo para el movimiento
a la derecha, arriba y abajo.
if pulsado[pygame.K_LEFT]: Para que cuando no se toque ninguna
jugador_vel_x = -3 flecha, al principio estas variables
moviendose_izquierda = True están todas en False.
if pulsado[pygame.K_RIGHT]:
P á g i n a 128 | 145
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 Actualizamos las coordenadas del
jugador.
# Lógica
jugador_rectangulo.x += jugador_vel_x
jugador_rectangulo.y += jugador_vel_y

if jugador_rectangulo.x > ANCHO - 60:


jugador_rectangulo.x = ANCHO - 60
if jugador_rectangulo.x < 0: Controlamos que
no se sale de la
jugador_rectangulo.x = 0
ventana.
if jugador_rectangulo.y > ALTO - 60:
jugador_rectangulo.y = ALTO - 60
Comprobamos las
if jugador_rectangulo.y < 0: colisiones habitación[0]
jugador_rectangulo.y = 0 son los límites.

for limite in habitacion[0]:


if jugador_rectangulo.colliderect(limite[1]):
jugador_rectangulo.x -= jugador_vel_x
jugador_rectangulo.y -= jugador_vel_y

for fruta in copy.copy(habitacion[1]): habitación[1]


if son las frutas.
jugador_rectangulo.collidepoint(fruta[1].centerx,
fruta[1].centery):
habitacion[1].remove(fruta)

for puerta in habitacion[2]:


if
jugador_rectangulo.collidepoint(puerta[1].centerx, habitación[2] son
las puertas.
puerta[1].centery):
if habitacion == habitacion1:
habitacion = habitacion2
jugador_rectangulo.x = 400
jugador_rectangulo.y = 60
else:
P á g i n a 129 | 145
habitacion = habitacion1 Pertenece al bucle
jugador_rectangulo.x = 560 anterior.
jugador_rectangulo.y = 620
# Dibujos
Mostramos todas las baldosas del
ventana.blit(imagen_fondo, (0,0)) mapa.

for elemento in habitacion:


for baldosa in elemento:
ventana.blit(baldosa[0], baldosa[1])

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.

Vamos a seguir con el proyecto del capítulo anterior.

Agregamos las imágenes del monstruo:

Creamos una nueva función:

Creamos el objeto monstruo_rectangulo de tipo rect, lo posicionamos con las coordenadas x e


y. La variable frames_monstruo lo inicializamos a 0.

En la lógica del monstruo.

Para que el monstruo se aproxime al jugador.

P á g i n a 135 | 145
Para que el monstruo no salga de la ventana.

La colisión con el monstruo.

Ahora los movimientos del monstruo.

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

def construir_mapa(superficie, mapa):


limites = []
frutas = []
puertas = []
x = 0
y = 0
for linea in mapa:
for baldosa in linea:
if baldosa == "M":
limites.append([baldosa_muro, pygame.Rect(x,y, 80, 80)])
elif baldosa == "S":
limites.append([baldosa_agua, pygame.Rect(x,y, 80, 80)])
elif baldosa == "A":
limites.append([baldosa_arbol, pygame.Rect(x,y, 80, 80)])
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()

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

if avistamiento(monstruo_rectangulo, jugador_rectangulo, 200):


if monstruo_rectangulo.x > jugador_rectangulo.x:
monstruo_rectangulo.x -=1
monstruo_izquierda = True
elif monstruo_rectangulo.x < jugador_rectangulo.x:
monstruo_rectangulo.x +=1
monstruo_derecha = True
elif monstruo_rectangulo.y > jugador_rectangulo.y:
monstruo_rectangulo.y -=1
monstruo_arriba = True
elif monstruo_rectangulo.y < jugador_rectangulo.y:
monstruo_rectangulo.y +=1
monstruo_abajo = True
else:
P á g i n a 141 | 145
monstruo_parado = True

if monstruo_rectangulo.x > ANCHO - 60:


monstruo_rectangulo.x = ANCHO - 60
if monstruo_rectangulo.x < 0:
monstruo_rectangulo.x = 0
if monstruo_rectangulo.y > ALTO - 60:
monstruo_rectangulo.y = ALTO - 60
if monstruo_rectangulo.y < 0:
monstruo_rectangulo.y = 0

# 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

if jugador_rectangulo.x > ANCHO - 60:


jugador_rectangulo.x = ANCHO - 60
if jugador_rectangulo.x < 0:
jugador_rectangulo.x = 0
if jugador_rectangulo.y > ALTO - 60:
jugador_rectangulo.y = ALTO - 60
if jugador_rectangulo.y < 0:
jugador_rectangulo.y = 0

for limite in habitacion[0]:


if jugador_rectangulo.colliderect(limite[1]):
jugador_rectangulo.x -= jugador_vel_x
jugador_rectangulo.y -= jugador_vel_y

for fruta in copy.copy(habitacion[1]):


if jugador_rectangulo.collidepoint(fruta[1].centerx,
fruta[1].centery):
habitacion[1].remove(fruta)

for puerta in habitacion[2]:


if jugador_rectangulo.collidepoint(puerta[1].centerx,
puerta[1].centery):
if habitacion == habitacion1:
habitacion = habitacion2
jugador_rectangulo.x = 400
jugador_rectangulo.y = 60
else:
habitacion = habitacion1
P á g i n a 142 | 145
jugador_rectangulo.x = 560
jugador_rectangulo.y = 620
# Dibujos

ventana.blit(imagen_fondo, (0,0))

for elemento in habitacion:


for baldosa in elemento:
ventana.blit(baldosa[0], baldosa[1])

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

# movimientos del jugador


if moviendose_derecha:
frames_jugador +=1
if frames_jugador >= 21:
frames_jugador = 1
if frames_jugador <6:
jugador_imagen = jugador1_der
elif frames_jugador < 11:
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
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

También podría gustarte