Curso de videojuegos con Pygame

Bucles infinitos con Pygame y control de FPS

Capítulo 4: Fondo en movimiento con bucle infinito y control de FPS

En este capítulo aprenderás a poner una imagen de fondo en movimiento gracias a un bucle infinito y de paso, te enseño a controlar las FPS del juego.

Utiliza el código del capítulo anterior para continuar con este.

En el código de este capítulo, he utilizado el propio bucle de Pygame para hacer que el fondo se vaya desplazando.
En el vídeo puedes ver una explicación bastante detallada de como funciona.

El control de FPS se utiliza para hacer que los frames (imágenes) pasen por la pantalla más rápido o más lento, de esa forma, podemos controlar a qué velocidad se mueve el juego, además de los elementos dentro de él como son el fondo, por ejemplo.

Cambiar los valores de tamaño de pantalla

Lo primero, antes de modificar el bucle del juego, es tener los tamaños de pantalla en variables. De este modo, podremos especificar detalles en el alto y ancho de la pantalla.

# Pantalla
ANCHO, ALTO = 1000, 600
PANTALLA = pygame.display.set_mode((ANCHO, ALTO))

¿Cómo optimizar las imágenes de Pygame?

Para optimizar las imágenes de Pygame tienes que utilizar en ellas la función convert(). Con optimizar me refiero a un menor consumo de recursos y por lo tanto, mejora del rendimiento del juego.

No te olvides de la línea del blit() siempre para mostrar el fondo.

# Fondo del juego
fondo = pygame.image.load("imagenes/ciudad.png").convert()
PANTALLA.blit(fondo, (0, 0))

¿Cómo hacer un fondo en movimiento con Pygame?

Hagamos un fondo en movimiento. Este lo tenemos que incluir dentro del bucle del juego para que se ejecute infinitamente.

Lo primero es almacenar los valores x e y del blit() para poder manejar estos dos valores.

# Fondo del juego
fondo = pygame.image.load("imagenes/ciudad.png").convert()
x = 0
y = 0
PANTALLA.blit(fondo, (x, y))

Los valores son iguales. Ahora, mueve esta línea del blit() hacia el bucle while.

En el vídeo, en el minuto 1:35 aproximadamente, he cometido un error. He dicho que pongas el blit() en el bucle for, pero como puedes ver tanto aquí como en el vídeo, lo estoy poniendo en el bucle while . Disculpen las molestias.
# Bucle de juego.
while True:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			sys.exit()
	PANTALLA.blit(fondo, (x, y))
	pygame.display.update()

De momento, aunque el fondo esté cargándose en el bucle, es estático, no se mueve.

Imagen de fondo en Pygame

Añadamos un decremento o incremento a x, es decir a las coordenadas horizontales. Con esto movemos el fondo en horizontal. Haz lo mismo con la y si quieres hacer el movimiento de arriba a abajo o de abajo a arriba.

En el caso de decrementar la x, se va a mover el fondo de derecha a izquierda. Si incrementas, a la inversa.

Yo voy a decrementar en un píxel cada ejecución del bucle. Antes de terminar este capítulo verás como hacer el control de FPS para manejar la velocidad a la que se mueve el fondo.

# Bucle de juego.
while True:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			sys.exit()
	PANTALLA.blit(fondo, (x, y))
	x -= 1
	pygame.display.update()

El resultado es un fondo que se queda borroso. hay que mejorar este movimiento.

Fondo en movimiento borroso Pygame

Añade una nueva variable. Con esta, vamos a obtener el ancho del rectángulo del fondo (fondo.get_rect().width). Le digo que me divida x entre ese valor y que me devuelva el resto.

En el blit(), cambia la x por x_relativa menos el cálculo del get_rect(). Esto nos da el valor de x_relativa - el ancho del fondo. El cálculo necesario para que se mueva el fondo correctamente.

# Bucle de juego.
while True:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			sys.exit()
	x_relativa = x % fondo.get_rect().width
	PANTALLA.blit(fondo, (x_relativa - fondo.get_rect().width, y))
	x -= 1
	pygame.display.update()

Con esto, no está todavía. La imagen ha mejorado algo, pero aún se sigue viendo casi todo borroso.

La solución a esto, es poner un if.

# Bucle de juego.
while True:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			sys.exit()
	x_relativa = x % fondo.get_rect().width
	PANTALLA.blit(fondo, (x_relativa - fondo.get_rect().width, y))
	if x_relativa < ANCHO:
		PANTALLA.blit(fondo, (x_relativa, 0))
	x -= 1
	pygame.display.update()

¿Cómo se controlan las FPS en Pygame?

Con esto último, está funcionando. No obstante, el fondo va muy rápido. Seguramente quieras poder controlar su velocidad. Esto es tan fácil como añadir un control de FPS "Frames Per Second" en inglés, "Imágenes Por Segundo en español".

Añade debajo de PANTALLA una variable con un número, el número de FPS que quieras que se carguen. Puesto que estamos decrementando el fondo en un píxel, cada frame, mueve una línea horizontal de 1 pixel de ancho. La velocidad con el número de FPS es relativa, dependiendo de la cantidad de incremento o decremento que hay en el bucle.

# Pantalla
ANCHO, ALTO = 1000, 600
PANTALLA = pygame.display.set_mode((ANCHO, ALTO))
FPS = 60
RELOJ = pygame.time.Clock()

Añade el control de la velocidad en el bucle:

# Bucle de juego.
while True:
	# Cerrar Juego
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			sys.exit()
	# Movimiento del fondo
	x_relativa = x % fondo.get_rect().width
	PANTALLA.blit(fondo, (x_relativa - fondo.get_rect().width, y))
	if x_relativa < ANCHO:
		PANTALLA.blit(fondo, (x_relativa, 0))
	x -= 1
	# Control de FPS
	RELOJ.tick(FPS)
	# Actualización de la ventana
	pygame.display.update()

En el vídeo puedes apreciar los cambios de velocidades. Te recomiendo que lo veas para entender bien como funciona esto.

Tal y como te he dicho, si incrementas en el bucle, puedes mover el fondo a otra dirección.

Al final del capítulo, en el vídeo, te digo que pruebes de mover el fondo de arriba a abajo o de abajo a arriba. Con esta imagen de fondo no queda bien, porque está hecha para moverse en horizontal. Si no lo has conseguido, te doy aquí la respuesta.

Haz click aquí para descargar un fondo de espacio que quedará bien para el movimiento vertical.

He redimensionado la imagen como he hecho con la otra y le he añadido algo de brillo con Photoshop, ya que está muy apagada. Si no te gusta, descarga cualquier otra imagen.

El bucle de juego tiene que quedar así:

# Bucle de juego.
while True:
	# Cerrar Juego
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			pygame.quit()
			sys.exit()
	# Movimiento del fondo
	y_relativa = y % fondo.get_rect().height
	PANTALLA.blit(fondo, (x, y_relativa - fondo.get_rect().height))
	if y_relativa < ALTO:
		PANTALLA.blit(fondo, (0, y_relativa))
	y += 1
	# Control de FPS
	RELOJ.tick(FPS)
	# Actualización de la ventana
	pygame.display.update()

Comentarios

Si te quedan dudas sobre el temario, sobre Python, Pygame o cualquier otra cosa relacionada o simplemente quieres agradecer, aquí tienes tu sitio para dejar tu granito de arena. Gracias por tus comentarios y por darle vida a este sitio web.

Programación Fácil YouTube

Suscríbete

Si te ha gustado este curso y crees que el trabajo merece la pena, te agradeceré eternamente que te suscribas a mi canal de YouTube para apoyarme y que pueda seguir haciendo cursos gratuitos.

Además, si te encanta la programación, tienes un montón más de cursos gratuitos para ver.

No solo eso, podrás participar enviándome comentarios con tus sugerencias para temas específicos o cursos completos o incluso las dudas que tengas y las intentaré ir resolviendo en los cursos que estén todavía abiertos.