🎃 Grandes descuentos en libros en línea, eformaciones y vídeos*. Código CALABAZA30. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Pygame
  3. Estructura de un juego Pygame
Extrait - Pygame Iníciese en el desarrollo de videojuegos en Python
Extractos del libro
Pygame Iníciese en el desarrollo de videojuegos en Python Volver a la página de compra del libro

Estructura de un juego Pygame

Introducción

En el capítulo anterior presentamos un primer ejemplo sencillo basado en Pygame. Esto nos permitió introducir de manera concreta la noción de bucle de juego, en el que vamos a profundizar en este capítulo.

En primer lugar, estudiaremos la estructura habitual de un videojuego Pygame. De esta manera, veremos cómo podemos inicializar el juego, definir la pantalla y, por tanto, el espacio dedicado al juego. También veremos cómo implementar un bucle de juego y gestionar el tiempo. Finalmente, explicaremos cómo se maneja el proceso de refresco en Pygame. Aprovecharemos para explicar la gestión de colores en código RGB (Red-Green-Blue), así como el sistema de coordenadas que se utiliza. Un sistema de coordenadas es el que nos permite identificar la ubicación precisa de un objeto dentro de la ventana del juego.

El objetivo aquí es adquirir todos los conocimientos básicos necesarios para afrontar correctamente el capítulo Diseño y grafismo en todos sus estados con Pygame.

Inicialización

Como cualquier módulo o librería utilizada en un programa Python, debe importar Pygame:

import pygame 

Al principio del programa, se trata de inicializar Pygame escribiendo la siguiente línea:

pygame.init() 

Ayuda en la línea de comandos

Por supuesto, cada vez que utilice una función de Pygame, puede intentar obtener más información sobre la sintaxis y los argumentos esperados consultando la ayuda en línea.

Por ejemplo, la documentación relacionada con pygame.init() está disponible en la dirección https://www.pygame.org/docs/ref/pygame.html#pygame.init

Pero también se puede obtener información directamente en el terminal de Python, utilizando el comando help. Por ejemplo, si escribe esto:

help("pygame.init") 

Obtenemos esta breve descripción de la función y su uso.

pygame.init = init(...) 
   init() -> (numpass, numfail) 
   initialize all imported pygame modules 

Visualización de la ventana

La gestión del tiempo viene inmediatamente a la mente cuando se piensa en diseñar un videojuego. Sin embargo, la gestión del espacio es igual de importante.

De hecho, es necesario pensar en el perímetro físico del juego y, por lo tanto, definir muy rápidamente el tamaño de la ventana del juego. De esta manera, gracias a la función set_mode, definimos una ventana de 600 píxeles de ancho por 400 píxeles de alto. También proponemos añadir un título en la ventana, gracias a la función set_caption.

VENTANA = pygame.display.set_mode((600, 400)) 
pygame.display.set_caption("Mi ventana") 

Tenga en cuenta que escribir ((600, 400)) significa que se pasa una tupla como argumento. Volveremos sobre esta noción de tupla más adelante.

¿Qué más puede hacer set_mode? Es suficiente con consultar la ayuda para averiguarlo. Escriba esta instrucción en la línea de comandos:

help("pygame.display.set_mode") 

Y obtiene la siguiente información:

pygame.display.set_mode = set_mode(...) 
   set_mode(size=(0, 0), flags=0, depth=0, display=0) -> Surface 
   Initialize a window or screen for display 

Vemos que además de la tupla size que ya utilizamos, tenemos otros argumentos, como los flags, que son particularmente útiles....

Recordatorios respecto al bucle de juego

Un bucle de juego (game loop) es un bucle infinito que se interrumpirá al cumplir ciertos criterios. La noción está asociada de alguna manera con una especie de reloj interno del juego. De esta manera, en cada iteración del bucle del juego podemos mover a un personaje o tener en cuenta que un objeto ha alcanzado a otro o que se ha cruzado la línea de llegada, lo que quiere decir que la partida ha terminado. Por lo tanto, cada iteración es una oportunidad para actualizar todos los datos relacionados con el estado actual de la partida. Esquemáticamente, en cada iteración se realizan las siguientes tareas:

1. Comprobar que no se alcanzan las condiciones de parada, en cuyo caso se interrumpe el bucle.

2. Actualizar los recursos necesarios para la iteración actual.

3. Obtener las entradas del sistema o de la interacción con el jugador.

4. Actualizar todas las entidades que caracterizan el juego.

5. Refrescar la pantalla.

Superficies Pygame

1. Definición de una superficie

En Pygame la noción de superficie es fundamental, porque la manipulación de este elemento geométrico es un aspecto importante y consecuente del desarrollo de videojuegos. Una superficie es una línea o un polígono que se muestra en la pantalla. Este polígono se puede rellenar de color o no. Apenas hay límites en las dimensiones de una superficie Pygame, ni siquiera límites en el número de superficies que se pueden manipular en el juego. Por lo tanto, se entiende que una parte importante de la gestión gráfica consistirá en crear y manipular superficies de Pygame. 

En Pygame, la superficie se corresponde con la visualización de un polígono de color o una línea discontinua o una imagen (como en el ejemplo Cohete y planetas del capítulo Conceptos del videojuego y primeros pasos con Pygame), o la visualización de texto superpuesto. Estos pocos ejemplos son implementaciones de superficies de Pygame.

Una superficie se crea de diferentes maneras, dependiendo del tipo de superficies que desee mostrar:

  • image.load() cuando se trata de una imagen.

  • font.render() cuando se trata de mostrar texto.

  • pygame.Surface() para una superficie que no es nada especial para la creación.

  • pygame.display.set_mode() para la ventana del juego, que también es una superficie (un poco particular).

La página de documentación...

Gestión del color

La gestión del color es un problema relacionado con las superficies cuyo interior algunas veces queremos colorear, pero es específico del desarrollo de Pygame en general y, por extensión, del desarrollo de Python.

Si volvemos a este fragmento de código:

azul = (0, 0, 255) 
azul_superficie.fill(azul) 

Vemos que un color se define por una tupla de tres cantidades numéricas. Cada una de estas cantidades es un número entero entre 0 y 255, lo que permite 256 valores posibles.

Tenemos 2563 (256 elevado a 3) posibilidades, por lo que en total hay 16 777 216 posibles variaciones de color. Esto es mucho más de lo que el ojo humano puede distinguir.

Este sistema de codificación se llama codificación RGB (Red Green Blue, rojo-verde-azul). De hecho, cada componente de la tupla es, respectivamente, una modificación de rojo, verde y azul.

De esta manera:

(0, 0, 0) se corresponde con el negro.

(255, 255, 255) se corresponde con el blanco.

(255,0, 0) se corresponde con el rojo primario.

(0, 255, 0) se corresponde con el verde primario.

(0, 0, 255) se corresponde con el azul primario.

Hay muchas aplicaciones en línea que permiten elegir la tupla correspondiente al color deseado. Puede ver un ejemplo en la dirección: https://www.rapidtables.com/web/color/RGB_Color.html

La documentación del módulo Color de Pygame está disponible en el capítulo Principales...

Sistema de coordenadas

Consideramos un sistema de coordenadas ortonormal, cuyo origen (0,0) es el punto superior izquierdo de la ventana del juego. El eje horizontal x es el eje orientado de izquierda a derecha, mientras que el eje vertical y está orientado de arriba a abajo.

Modifiquemos un poco el código anterior para mostrar una superficie rectangular nueva, roja esta vez, que permite especificar las diferentes coordenadas involucradas.

import pygame 
 
azul = (0, 0, 255) 
rojo = (255, 0, 0) 
 
pygame.init() 
pygame.display.set_caption(u'Surface') 
ventana = pygame.display.set_mode((400, 400)) 
 
azul_superficie = pygame.Surface((400, 400)) 
azul_superficie.fill(azul) 
 
rojo_superficie = pygame.Surface((120, 240)) 
rojo_superficie.fill(rojo) 
 
ventana.blit(azul_superficie, (0, 0)) 
ventana.blit(rojo_superficie, (50, 100)) 
 
pygame.display.flip() 
 
while True: 
 event = pygame.event.wait() 
   if event.type == pygame.QUIT: 
     break 
 
pygame.quit() 

No cambiamos nada en la visualización de la ventana, cuyo fondo es siempre azul. Al contrario, añadimos un rectángulo rojo dentro de esta ventana.

El posicionamiento de los puntos superiores izquierdos de los rectángulos, se realiza gracias a la función blit. La función flip provoca el refresco...

Gestión del tiempo y los eventos

1. Gestión del tiempo en Pygame

La gestión del tiempo es la relación con el tiempo, que tiene una gran importancia en el desarrollo de videojuegos y, por lo tanto, obviamente en Pygame.

La documentación del módulo time de Pygame está disponible en el capítulo Principales módulos de Pygame.

Este módulo ofrece varias funciones que permiten cronometrar la sesión actual (desde el init) o pausar la ejecución, por ejemplo. Para hacer esto se utilizan las dos funciones siguientes: 

  • pygame.time.get_ticks

  • pygame.time.wait o pygame.time.delay

El módulo pygame.time también incluye un objeto Clock, que permite ir más allá en la gestión del tiempo. La documentación oficial en línea para este objeto Clock está en: https://www.pygame.org/docs/ref/time.html#pygame.time.Clock

Tenga en cuenta que, en términos de tipografía, la nomenclatura de las funciones en Pygame comienza con una letra minúscula. La nomenclatura de los objetos (como Surface o Clock) comienza con una letra mayúscula. Esta es una buena manera de saber, de un solo vistazo, con qué tipo de objeto estamos trabajando.

La función tick de Clock (pygame.time.Clock.tick) permite actualizar el reloj asociado con el juego actual. Se llama cada vez que se actualiza la pantalla del juego y tick permite especificar el número máximo de fotogramas (imágenes) que se muestran por segundo y, por lo tanto, limitar y controlar la velocidad de ejecución del juego.

Por lo tanto...

Los códigos globales de los dos ejemplos

1. Primer ejemplo

El código del primer ejemplo (FIL.py), que se corresponde con la visualización mediante el sistema de coordenadas, es el siguiente.

import pygame 
 
azul = (0, 0, 255) 
rojo = (255, 0, 0) 
 
pygame.init() 
pygame.display.set_caption(u'Superficie') 
ventana = pygame.display.set_mode((400, 400)) 
 
azul_superficie = pygame.Surface((400, 400)) 
azul_superficie.fill(azul) 
 
rojo_superficie = pygame.Surface((120, 240)) 
rojo_superficie.fill(rojo) 
 
ventana.blit(azul_superficie, (0, 0)) 
ventana.blit(rojo_superficie, (50, 100)) 
 
pygame.display.flip() 
 
while True: 
   event = pygame.event.wait() 
   if event.type == pygame.QUIT: 
       break 
 
pygame.quit() 

2. Segundo ejemplo

A continuación, se muestra el código global del "cuadrado que rebota":

import sys 
import pygame 
 
rojo = 255, 0, 0 
azul = 0, 0, 255 
 * 
pygame.init() 
ventana = pygame.display.set_mode((400, 400)) 
pygame.display.set_caption("El cuadrado que rebota") 
 
clock = pygame.time.Clock() 
 
XX = 300 
MOVIMIENTO = 3 
 
while 1: 
   clock.tick(50) 
 
   for event in pygame.event.get(): ...