top of page
Buscar

2. Nuestro Primer Programa en Pygame

  • Foto del escritor: Fernando Sansberro
    Fernando Sansberro
  • 17 oct 2021
  • 22 Min. de lectura

Actualizado: 25 dic 2021

En este capítulo comenzaremos hablando de los lenguajes de programación disponibles para hacer videojuegos, y nos centraremos en el lenguaje Python y en la librería para juegos Pygame, que son los que utilizaremos en este libro.


Durante este capítulo construiremos el esqueleto de un juego, con un bucle principal (el game loop), y al final del capítulo ya tendremos todo pronto como para comenzar a agregar objetos que se muevan por la pantalla.


A medida que se avanza en el libro, lo que vayamos programando en cada capítulo nos servirá de base para todos los juegos que hagamos en el futuro.


¿En qué lenguajes se programa un juego?


Existen varios lenguajes de programación, como por ejemplo, C++, C#, Java, Actionscript, Python, LUA, JavaScript, etc., que son los lenguajes más comunes para desarrollar videojuegos.


En lenguajes de bajo nivel, como por ejemplo el lenguaje C++, lleva muchas líneas de código para lograr hacer que algo aparezca en la pantalla. En general, cuando una tarea lleva muchas líneas de código, los programadores hacen módulos (bibliotecas o librerías) que podemos utilizar a través de llamadas a funciones, para hacer las cosas más fáciles sin saber los detalles que hay internamente.


En lenguajes de más alto nivel, como LUA, es más sencillo programar, dado que con menos sentencias realizamos más cosas. Cada lenguaje, por supuesto, tiene sus pros y sus contras.


Librerías Gráficas y APIs


Hace muchos años, cuando se quería hacer un videojuego, había que trabajar directamente con el hardware. Por ejemplo, si queríamos mostrar una imagen, debíamos acceder directamente a la tarjeta de video, y esto era muy complicado, porque cada tarjeta era diferente, había varias tarjetas en el mercado, y había que programar a cada una por separado.


Al principio se programaba en lenguaje Assembler, un lenguaje de códigos muy cercanos al código que ejecuta el procesador. Había que programar en este lenguaje porque era lo único suficientemente rápido para hacer juegos. La dificultad que traía esto es que había que escribir muchas líneas de código para hacer algo puntual, y que cada procesador y computadora eran diferentes, por lo cual había que reescribir el código para cada máquina.


A medida que fue pasando el tiempo, y que las computadoras fueron siendo cada vez más rápidas, fue posible utilizar lenguajes de más alto nivel. Al principio, lenguajes como C++ y Pascal, y hoy día tenemos lenguajes como C#, Java, Actionscript, Python, JavaScript o LUA, por nombrar a los más utilizados para juegos.


Con cada lenguaje, utilizaremos lo que se conoce como módulos o bibliotecas (library en inglés) o a veces se les llama librerías, que son un conjunto de módulos y/o funciones para realizar determinadas tareas. También utilizaremos lo que se conoce como APIs (Application Programming Interface), que son librerías que le permiten al programador trabajar con el hardware de una forma más abstracta, a más alto nivel. De esta forma, por ejemplo, podemos mostrar una imagen en la pantalla, usando una sola línea de programación, invocando a una función de la librería gráfica que en realidad hace un montón de cosas complejas a nivel del procesador de la máquina, y que no necesitamos saber en detalle qué es lo que hace internamente.


Entonces, para programar un juego, necesitamos saber programar una de estas APIs. Sin esto, no podríamos acceder a la parte gráfica ni al sistema de audio de la computadora, por ejemplo.


Entre las APIs más comunes para programar videojuegos se encuentran las que nos proporcionan los fabricantes de los sistemas operativos, siendo las más comunes DirectX (creada por Microsoft para el sistema operativo Windows), OpenGL (es una biblioteca de código abierto, que funciona en varios sistemas operativos) y SDL (también de código abierto y para varias plataformas).


Nota: Cuando un lenguaje, API o videojuego funciona en varios sistemas operativos, se dice que es multiplataforma. Se denomina plataforma a un entorno, máquina o lenguaje, o incluso a la combinación de ellas. Por ejemplo, las plataformas comunes para correr videojuegos son PC (Windows), Mac, Linux, Web, iOS, Android, Consolas, etc.


Pygame y SDL


Cada biblioteca gráfica tendrá su versión para diferentes lenguajes de programación. La biblioteca que vamos a utilizar es SDL (Simple Directmedia Library), que está escrita en lenguaje C, es muy poderosa, es multiplataforma, es gratuita y es de código abierto.


Como estaremos programando en lenguaje Python, no podremos acceder a SDL directamente, dado que SDL está programada en lenguaje C. Ahí es donde entra Pygame, que es lo que se conoce como un wrapper de SDL. Esto quiere decir que es un conjunto de funciones en Python que se comunica con el lenguaje C de SDL.


Para poder trabajar con Python y Pygame, deberemos instalarlos en la computadora. Más adelante veremos cómo hacer esto.


Figura 2-1: Esquema de las capas de software.



Por ejemplo, supongamos que queremos crear una ventana para el juego. Si usáramos una biblioteca de bajo nivel (o sea, más cercana al hardware de la computadora), la forma de hacerlo sería distinta para cada plataforma. Deberíamos usar diferente programación para cada una.


Al utilizar un lenguaje de alto nivel (o sea, más abstraída del hardware de la computadora), junto con una biblioteca de alto nivel, las tareas se realizan de la misma manera para todas las diferentes plataformas. Entonces, para crear una ventana, simplemente llamaríamos a una función que hará la tarea, e internamente se encargará de cosas que no nos interesa saber cómo funcionan en detalle y que tienen relación con el hardware.


Por ejemplo, para crear la ventana llamaremos a una función del estilo:


screen = pygame.display.set_mode(...)

Internamente se realizan tareas relacionadas con el hardware de la computadora para que la ventana sea creada y se ponga visible. De esta forma simple, escribimos en lenguaje Python y llamamos a una función de Pygame para crear la ventana. Esta función se comunica con SDL y utiliza la función de SDL correspondiente para crear la ventana, y a su vez SDL se comunica con el sistema operativo para indicarle que cree la ventana. Esta cadena o estructura de capas, se puede ver en la figura 2-1.


Esta es una de las grandes ventajas de usar una API como Pygame. O sea, escribiremos el programa una sola vez y luego lo llevaremos fácilmente a otras plataformas. Siempre tendremos que tener en cuenta factores inevitables como diferentes resoluciones de pantalla, o diferentes controles, pero es mejor adaptar el programa, a que tener que escribirlo todo nuevamente.


Nota: A la acción de programar un juego y luego modificarlo para que corra en otra plataforma se le llama portar el juego.


Cómo Instalar Python y Pygame


Antes de comenzar a trabajar con Python y Pygame, debemos instalarlos en la computadora.


Para instalar Python, hay que ir al sitio https://www.python.org/, descargar la última versión de Python para el sistema operativo que usemos, e instalarlo. A la hora de escribir este libro se usó Python 3.10.0.


Por ejemplo, para instalar en el sistema operativo Windows, debemos ejecutar el instalador que descargamos, y seleccionar la opción “Add Python to environment variables". Con esto, podremos ejecutar Python desde la terminal de comandos.


Ante cualquier duda, podemos consultar cómo instalar Python desde la web del mismo, o pedirle ayuda a un profesor de informática, o a algún programador.

Para instalar Pygame hay que ir al sitio http://www.pygame.org y seguir las instrucciones para su instalación en el sistema operativo que usemos.

Para instalar Pygame en Windows, la forma más sencilla es escribir el siguiente comando en la terminal de comandos:


py -m pip install -U pygame --user

Este libro y los programas de ejemplo fueron creados utilizando Python 3.10.0 y Pygame 2.0.2, que eran las últimas versiones disponibles al momento de escribir este libro. De todas formas, se ha tratado, dentro de lo posible, no usar programación que dependa de versiones específicas. Si usáramos una versión diferente de Python o Pygame, algunas cosas podrían no funcionar y habría que corregirlas, pero el cambio a realizar debería ser mínimo.


Nota: Para ver la versión de Python instalada en el sistema, abrir la terminal de comandos y ejecutar el siguiente comando en la carpeta donde se instaló: python -V. Cuando se entra a la consola de Python (escribiendo python en la terminal de comandos, o abriendo el programa IDLE en Windows) se muestra un mensaje con la versión de Python. Para ver la versión de Pygame instalada, una vez dentro de la consola de Python, escribimos las sentencias: import pygame, y luego print (pygame.ver).


Principales Características de Pygame


Pygame es una biblioteca que contiene varios módulos, cada uno con muchas funciones para trabajar con los distintos aspectos que tiene un juego, entre los cuales se encuentran:


- Manejo del Display (la pantalla).

- Manejo de Superficies (Imágenes y objetos Rects).

- Manejo de la Entrada (Teclado, Mouse, Joystick, etc.).

- Sprites (manejo de grupos de sprites, colisiones, etc.).

- Audio.

- Módulos con utilidades (manejo del tiempo, transformaciones, etc.).


Iremos viendo por partes, cada una, a medida que vayamos introduciendo nuevas funcionalidades en nuestro videojuego. También se irán explicando los términos utilizados en el desarrollo de videojuegos, a medida que aparezcan.


En este punto ya sabemos en dónde estamos parados en lo que respecta a Python y Pygame. ¡Ya podemos comenzar a aprender a programar nuestro primer videojuego!


Los Programas de Ejemplo y el Editor


La mejor forma de aprender a programar videojuegos es, justamente, programando videojuegos y probando cosas nuevas en él. De la misma manera, la mejor forma de aprender a utilizar un lenguaje como Python y una biblioteca como Pygame, es escribir nuestros propios programas con ellos y practicar mucho.


El libro contiene los ejemplos ya armados, para poder ejecutarlos, modificarlos y de esta forma aprender con la práctica. Debes tener la habilidad de escribir el texto del programa utilizando algún editor de texto y poder ejecutarlo y ver el resultado. Un programa se puede escribir utilizando un editor de texto sin formato y se puede usar la terminal para ejecutar el programa. Si no puedes escribir y ejecutar un programa Python, debes pedirle asistencia a un docente o a un experto. Una vez que puedas escribir un programa y ejecutarlo, el resto es sencillo. En Windows, se puede usar el editor IDLE que viene incluido con la instalación de Python.


Nota: Los ejemplos y materiales que acompañan el libro pueden ser descargados del sitio web: www.fsansberro.com.


Los ejemplos se encuentran clasificados por capítulos, de forma tal que sea sencillo ubicarlos. Cuando el libro utilice uno de estos ejemplos, se indicará dónde está ubicado para su fácil localización.


Para ejecutar los ejemplos y en general para programar en Python, no es necesario usar ningún editor en especial, aunque ayuda mucho el uso de un entorno de desarrollo integrado (lo que se conoce como IDE, por las iniciales de Integrated Development Environment).

Un excelente editor para Windows, es PyCharm (https://www.jetbrains.com/pycharm).


Nuestro Primer Programa con Pygame


A continuación escribiremos un programa que será el esqueleto básico de todo videojuego que hagamos con Pygame. Escribiremos el game loop o bucle principal del juego.


Comencemos por ejecutar el primer ejemplo, el cual se encuentra en la carpeta: capitulo_02\001_game_loop. Para ver el ejemplo en funcionamiento, debemos ejecutar el archivo main.py.


Al ejecutar este programa solamente veremos una ventana azul. Si pulsamos la tecla [Esc] el programa se termina y la ventana se cierra. También podemos tocar en la cruz de la ventana para salir.


Para hacer cualquier videojuego, partiremos desde este esqueleto. A continuación se explicará cada una de las partes que componen nuestro primer programa, y que será la base para el resto. Pero primero, veamos el listado del programa completo:


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

#--------------------------------------------------------------------
# Ejemplo de game loop.
#
# Autor: Fernando Sansberro - Batovi Games.
# Proyecto: Hacete tu Videojuego.
# Licencia: Creative Commons. BY-NC-SA.
#--------------------------------------------------------------------

# Importar e inicializar Pygame.
import pygame
pygame.init()

# Crear la ventana y poner el tamaño.
screen = pygame.display.set_mode((640, 360))
# Poner el título de la ventana.
pygame.display.set_caption("Mi Juego")

# Crear la superficie del fondo o background.
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((0, 0, 255))

# Inicializar las variables de control del game loop.
clock = pygame.time.Clock()
salir = False

# Loop principal (game loop) del juego.
while not salir:

    # Timer que controla el frame rate.
    clock.tick(60)

    # Procesar los eventos que llegan a la aplicación.
    for event in pygame.event.get():
        
        # Si se cierra la ventana se sale del programa.
        if event.type == pygame.QUIT:
            salir = True

        # Si se pulsa la tecla [Esc] se sale del programa.
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_ESCAPE:
                salir = True

    # Actualizar la pantalla.
    screen.blit(imgBackground, (0, 0))
    pygame.display.flip()

# Cerrar Pygame y liberar los recursos que pidió el programa.
pygame.quit()

Si aún no has usado algún IDE, para escribir y ejecutar el programa, puedes crear el texto con un editor sin formato y luego, desde la consola de comandos, ejecutar python main.py, estando en el mismo directorio donde se encuentra el archivo main.py.


Si te encuentras en Windows, abre el programa con IDLE y ejecuta el programa (pulsando [F5] o mediante el menú Run | Run Module).


Si estás usando algún IDE como PyCharm, puedes pulsar con el botón derecho del mouse sobre el archivo main.py, abrirlo con PyCharm y ejecutarlo con el menú Run. En caso de no tener configurado el intérprete de Python, aparecerá una ventana donde podemos seleccionar la versión instalada.


Nota: Es muy importante escribir el programa nosotros mismos. Los ejemplos del libro están para poder consultar en caso que algo no nos funcione, pero nunca va a haber una mejor experiencia y una mejor forma de aprender que escribiendo nosotros mismos el código.



Figura 2-2: Ejecutando nuestro primer programa en Pygame.



Nuestro primer programa parece un programa grande, pero es chico comparado con uno que haga lo mismo en otros lenguajes, como por ejemplo en C++. Python es un lenguaje que permite hacer las cosas con bastante menos código.


Es muy importante escribir este programa y compilarlo para ver que funcione sin errores, y luego entender bien qué es lo que hace cada sentencia, lo cual se explicará a continuación.


El programa tiene básicamente dos partes. La primera parte carga e inicializa los elementos necesarios de Pygame para que el programa funcione, y la segunda parte consiste en el game loop o el bucle del juego propiamente dicho (la estructura while), que es en donde luego ocurrirá toda la acción del juego. A continuación se explica el programa paso a paso.


Inicializar Pygame


Antes que nada, lo primero que hay que hacer es importar el módulo pygame, para tener acceso a las funciones de Pygame. Luego de eso, debemos llamar a la función pygame.init() para inicializar la biblioteca Pygame.


# Importar e inicializar Pygame.
import pygame
pygame.init()

No podremos utilizar ninguna función de Pygame hasta que no hayamos invocado a pygame.init(), por lo cual esto es lo primero que debemos hacer en el programa.


Nota: Cuando necesites saber más acerca del funcionamiento de Pygame, o lo que hace alguna función en particular, consulta la documentación online en el siguiente sitio: http://www.pygame.org/docs/. Consultar la documentación es una excelente forma de profundizar los conocimientos sobre un tema en particular y aprender.


Establecer el Modo de Video


Lo que sigue luego de inicializar Pygame es inicializar el modo de video. Los videojuegos generalmente utilizan un modo de video dedicado. Esto consiste en decir si el juego correrá en una ventana o en la pantalla completa. Si es en una ventana, necesitamos indicar su tamaño, y si se trata de pantalla completa, necesitamos indicar su resolución. En ambos casos debemos pasarle dos números a la función: el ancho y el alto en píxeles.


En las computadoras PC, por ejemplo, podremos correr el juego en pantalla completa y a determinada resolución de pantalla (esto se conoce como el modo de video, por ejemplo: 640 x 480, 800 x 600, 1024 x 768 píxeles, etc.). Cuando corremos el programa en una ventana, decimos que lo corremos en “modo ventana”. Cuando lo corremos en la pantalla completa, decimos que lo corremos en “modo pantalla completa” (fullscreen).

Lo que haremos con nuestro primer programa, será correrlo en modo ventana, con un tamaño de 640 x 360 píxeles. Hemos elegido esta resolución baja porque los juegos que haremos en esta serie de libros son con estilo pixel art.


# Crear la ventana y poner el tamaño.
screen = pygame.display.set_mode((640, 360))
# Poner el título de la ventana.
pygame.display.set_caption("Mi Juego")

Con la primera sentencia decimos que el modo de video va a ser en ventana, a una resolución de 640 x 360 píxeles. La función pygame.display.set_mode() recibe como parámetro una tupla con el tamaño de la ventana. En Python, una tupla son valores separados con coma, delimitados entre paréntesis. Más adelante veremos cómo hacer que el juego corra en pantalla completa.


La función pygame.display.set_caption() sirve para ponerle un título a la ventana (el título de la aplicación o juego). Cuando ejecutamos el programa, vemos que la ventana tiene como título el texto que le pasamos como argumento a esta función.


Nota: Recuerda que cuando pasamos valores a una función, a estos valores se le llaman argumentos y cuando la función los recibe se les llama parámetros. Hoy día se estila mucho usar solo la palabra parámetro, que es la que usaremos en el libro, tanto para referirnos al valor que se pasa como al parámetro que lo recibe.


Crear la Superficie del Fondo


Una superficie es un rectángulo en memoria en el cual se puede dibujar (se puede decir que es sinónimo de una “imagen en la memoria”). Necesitamos tener una imagen que va a ser la que utilizaremos para el fondo de la ventana. Entonces, creamos una superficie del mismo tamaño de la ventana y la llenamos con el color azul (color RGB: 0, 0, 255).


# Crear la superficie del fondo o background.
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((0, 0, 255))

La sentencia pygame.Surface() crea una nueva superficie y tiene como parámetro el tamaño de la superficie que vamos a crear (una tupla con el ancho y el alto en píxeles). En este caso le pasamos screen.get_size() para que sea del mismo tamaño que tiene la ventana (screen.get_size() nos retorna una tupla con el ancho y alto de la ventana). La referencia a la superficie creada se almacena en la variable imgBackground.


La sentencia imgBackground.convert() convierte el formato de la imagen al formato de Pygame (al formato de la pantalla). Debemos hacer esto para todas las imágenes que creamos o que cargamos, porque por ejemplo si una imagen tiene un formato con compresión (como es el caso de imágenes PNG o JPG), al mostrar la imagen, Pygame tiene que descomprimirla y eso demora. Por esta razón, siempre utilizaremos la función convert() luego de crear o cargar cualquier imagen.


Por último, la sentencia imgBackground.fill((0, 0, 255)) lo que hace es llenar la imagen con el color (0, 0, 255), lo que corresponde a rojo = 0, verde = 0 y azul = 255, o sea, el color azul puro. Esta forma de indicar un color se denomina formato de color RGB, y está dado por tres valores correspondientes a los componentes rojo, verde y azul (en inglés: red, green, blue). Más adelante veremos cómo se codifican los colores con el formato RGB.


Nota: La explicación en este libro siempre tenderá a ser lo más simple posible, de forma que sea sencillo y práctico de seguir. Recuerda que para profundizar en cualquier función de Pygame, o conocer en profundidad lo que hace Pygame en su interior, es necesario recurrir a la documentación online en el sitio: http://www.pygame.org/docs/.


La Inicialización del Juego


Hemos visto que el código que se ejecuta antes del game loop se encarga de inicializar todos los elementos que son necesarios en el programa. En un juego grande, esto incluirá inicializar los assets (los gráficos, los sonidos, los niveles, etc.). No es conveniente cargar o inicializar objetos o elementos cuando el juego mismo está corriendo, porque sino el juego se podría trancar un instante (porque por ejemplo necesita acceder al disco y leer). Por este motivo, siempre habrá una etapa de inicialización antes de comenzar el juego en sí.


Una vez inicializado todo lo necesario, entramos al game loop para que corra el juego en sí (en este ejemplo, el juego no hará nada, pero ya dejaremos pronta la base para hacer un juego).


Estas dos líneas inicializan las variables que controlarán el loop principal del juego (el game loop):


# Inicializar las variables de control del game loop.
clock = pygame.time.Clock()
salir = False

En la primera línea, inicializamos el reloj (creamos un objeto Clock), que en el game loop va a hacer latir al juego 60 veces por segundo (el juego va a correr a 60 FPS). Luego, la variable salir hará que se salga del game loop cuando esta variable valga True, lo cual ocurrirá cuando se pulse la tecla [Esc] o cuando se cierre la ventana.


El Game Loop


Llegamos a la parte principal del programa: el game loop. El game loop es una estructura while, de la cual no se sale hasta que la variable salir sea True. El game loop correrá en forma continua 60 veces por segundo hasta que el usuario cierre la ventana o decida salir pulsando la tecla [Esc]. Veamos el código del game loop y luego explicaremos una a una sus sentencias.


# Loop principal (game loop) del juego.
while not salir:

    # Timer que controla el frame rate.
    clock.tick(60)

    # Procesar los eventos que llegan a la aplicación.
    for event in pygame.event.get():
        
        # Si se cierra la ventana se sale del programa.
        if event.type == pygame.QUIT:
            salir = True

        # Si se pulsa la tecla [Esc] se sale del programa.
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_ESCAPE:
                salir = True

    # Actualizar la pantalla.
    screen.blit(imgBackground, (0, 0))
    pygame.display.flip()

El flujo del programa se puede ver en la figura 2-2. Básicamente se ejecuta una estructura while mientras la variable salir sea False. Se sale del game loop cuando la variable salir es True. Dentro del game loop, lo que se hace es manejar los eventos, mover los objetos del juego y dibujarlos (esto se hará más adelante cuando agreguemos los objetos del juego). Al final, se limpia la memoria usada por los objetos creados por el programa.


Figura 2-3: Diagrama de flujo de nuestro primer programa Pygame.



A continuación se explicará paso por paso las sentencias que componen nuestro game loop y veremos algunos conceptos necesarios.


El Reloj


La primera línea del game loop, es clock.tick(60). Lo que hace esta sentencia es esperar el tiempo necesario para que el game loop (y por lo tanto, el juego) corra a 60 frames por segundo. Se hace esto para que el frame rate del juego sea constante.


Procesar los Eventos


Dentro del game loop, en cada pasada del ciclo, procesamos los eventos de la aplicación (esto es, los eventos que el sistema operativo le envía a nuestra ventana).


    # Procesar los eventos que llegan a la aplicación.
    for event in pygame.event.get():
        
        # Si se cierra la ventana se sale del programa.
        if event.type == pygame.QUIT:
            salir = True

        # Si se pulsa la tecla [Esc] se sale del programa.
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_ESCAPE:
                salir = True

Con estas sentencias, estamos capturando el evento pygame.QUIT que es el evento que el sistema operativo le envía a la aplicación (a nuestro juego) cuando se cierra la ventana.

También estamos chequeando si se pulsa la tecla [Esc]. Si ocurre alguna de estas condiciones, la variable salir se pondrá en True, lo que hará que se salga del game loop.


En un capítulo más adelante, veremos en profundidad el manejo de eventos. Por ahora diremos que utilizando for event in pygame.event.get() se recorren todos los eventos que han ocurrido desde el frame anterior. Para cada evento en la lista de eventos, se pregunta si es el evento pygame.QUIT o el evento pygame.KEYUP el que ha llegado a la ventana. Si el evento es pygame.KEYUP, significa que se ha pulsado una tecla, por lo cual preguntamos si esa tecla es la tecla [Esc].


Si ocurre uno de estos eventos, se cambia la variable de control del game loop (salir) para que se salga del loop en el siguiente frame.


Más adelante veremos cómo en esta parte del game loop (denominada manejo de eventos), capturamos otros eventos, como por ejemplo cuando el jugador pulsa una tecla para moverse o disparar, pulsa o mueve el mouse, etc.


Refrescar la Pantalla


Luego de manejar los eventos, el programa movería los objetos del juego y luego los dibujaría en la pantalla. Como por ahora no hay objetos en el juego, pasamos a la parte que refresca la pantalla:


    # Actualizar la pantalla.
    screen.blit(imgBackground, (0, 0))
    pygame.display.flip()

Recordemos que imgBackground contiene la imagen del fondo (background) que usamos en el juego. La primera sentencia copia la imagen de background a la pantalla. Las coordenadas (0,0) es para decirle que la muestre en la posición (0,0), correspondiente a la esquina superior izquierda de la pantalla. Como la imagen tiene el mismo tamaño que la ventana, la sobreescribe completamente. Más adelante hablaremos sobre el sistema de coordenadas.


La sentencia pygame.display.flip() lo que hace es volcar a la pantalla del monitor (volcar al display) el contenido de la pantalla (todo lo que hemos dibujado en screen). Es necesario invocar a esta función, o de lo contrario no veríamos nada en la pantalla.


Liberar la Memoria al Final


Una vez que salimos del game loop, el programa deberá liberar los recursos que ha pedido al sistema (a esto se le llama liberar la memoria).


# Cerrar Pygame y liberar los recursos que pidió el programa.
pygame.quit()

La función pygame.quit() la llamaremos al final del programa y lo que hace es liberar de memoria los módulos de Pygame que se hayan inicializado. En este punto del programa deberemos, además, liberar los recursos que hemos pedido para nuestros objetos.


Con esto hemos terminado nuestro primer programa Pygame y hemos implementado el game loop, que será la base para nuestro primer juego. Ahora veremos algunos conceptos más y luego ya pasaremos a la parte de la acción, en la cual moveremos objetos por la pantalla.



Encoding


Si queremos poner tildes en los comentarios, debemos poner esta línea al principio de los archivos:


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

Como veremos en todos los ejemplos del libro, todos los archivos comienzan con esta línea. El editor que usemos para editar debe grabar el texto con encoding UTF-8.


Nota: En este libro escribiremos el código en inglés y los comentarios en español. El motivo de escribir el código en inglés es que es una práctica profesional, dado que es muy factible que se comparta el código con gente de otras nacionalidades y en la industria de videojuegos se espera que el programador escriba el código en inglés. Hemos puesto los comentarios en español para hacerlo más fácil al lector, pero cuando se trabaje profesionalmente, ha de escribirse en inglés.


¿Qué hace el Game Loop en un Videojuego?


En un videojuego hay muchos objetos (también llamados entidades) que se mueven en forma autónoma. ¿Cómo se logra esto?


Pues bien, el game loop es quien se encarga de eso. Como hemos visto, el game loop consiste en un bucle infinito (una estructura while), del cual se sale solamente cuando se termina el juego. En cada ciclo del loop, se actualiza la posición de cada objeto del juego y luego se dibuja en su nueva ubicación. La función que actualiza los objetos del juego se llamará update() y la función que los dibuja se llamará render(). Más adelante implementaremos estas funciones. Repasemos la estructura del game loop mirando la siguiente figura.


Figura 2-4: El game loop en pseudocódigo.



La primera parte del game loop corresponde a procesar los eventos y, por ejemplo, ver si el jugador ha pulsado alguna tecla o ha hecho algo con el mouse o joystick para controlar a su personaje. Luego la función update() recorrerá los objetos del juego uno a uno y los moverá según la velocidad que tengan, controlando las colisiones entre ellos y las reacciones. En el caso del personaje que controla el jugador, lo moverá según los controles.


Luego de movidos los objetos, se chequean las colisiones entre ellos para saber si algún objeto debe morir porque fue alcanzado por una bala, por ejemplo, o si se debe crear una bala porque el personaje ha disparado, o si un objeto debe eliminarse porque ha salido de la pantalla, etc. Al final de todo, se invoca a la función render() para dibujar a todos los objetos del juego en su nueva posición y luego se mostrará el frame actual en la pantalla.


A cada ciclo del game loop se le denomina update, que significa actualización. Cada paso del game loop corresponde a una invocación a las funciones update() y render(), y es lo que mantiene funcionando un videojuego.


Modo Fullscreen


Generalmente los juegos corren en modo de pantalla completa (denominado modo fullscreen) porque un juego que corre en pantalla completa, será más inmersivo (nos creeremos más la realidad del juego).


Veamos el segundo ejemplo, ubicado en la carpeta capitulo_02\002_fullscreen. Este ejemplo es el mismo que el anterior, pero agrega un parámetro al crear la ventana para crearla en modo fullscreen.


Si corremos el programa en PC, veremos que el programa se muestra en la pantalla completa. Si no funciona, para que corra, debería cambiarse la resolución a alguna soportada por la tarjeta de video (1920 x 1080, 1280 x 720 si es un notebook, etc.). Ya hablaremos sobre esto más adelante.


La única línea que cambia con respecto al ejemplo anterior, es cuando se inicializa el modo de video. Ahora se pasa un parámetro extra, pygame.FULLSCREEN, para indicarle a Pygame que queremos usar la pantalla completa.


# Poner el modo de video fullscreen e indicar la resolución.
screen = pygame.display.set_mode((640, 360), pygame.FULLSCREEN)

Nota: Recordemos que cuando una palabra aparece en mayúsculas es porque se trata de una constante. En este caso, la constante pygame.FULLSCREEN es necesaria para que Pygame sepa que queremos correr el juego en pantalla completa.


Hay que tener en cuenta que no todas las tarjetas de video pueden poner en fullscreen cualquier resolución que le indiquemos. Hoy día es posible que sí, pero existe la posibilidad de que falle (dando un error), sobre todo con equipos viejos o en hardware limitado. Las resoluciones históricas más comunes en modo fullscreen para PC son 640 x 480, 800 x 600, 1024 x 768, 1920 x 1080 píxeles, etc.


Nota: Cuando hagamos un videojuego para publicar, deberemos chequear que la resolución sea soportada por la computadora donde corre, y si no se soporta la resolución indicada, permitirle al jugador seleccionar una. Es seguro asumir que un PC soporta fullscreen en 640 x 480, u 800 x 600, que son resoluciones históricas. En modo ventana la mayoría de las tarjetas de video pueden manejar tamaños variables y no habrá errores.


Nota: En los ejemplos, utilizaremos el modo de ventana en 640 x 360, de modo que los mismos funcionen en todas las computadoras. Si se desea correr los ejemplos en fullscreen, hay que tener en cuenta que la resolución sea soportada por la tarjeta de video. Como el objetivo de este libro es enseñar las bases de la programación de videojuegos, nos olvidaremos de este tema hasta que debamos publicar el juego, y trabajaremos en una resolución de 640 x 360.


Cambiar entre modo Fullscreen y modo Ventana


En esta sección modificaremos el programa para que pulsando la tecla [F] podamos cambiar entre el modo fullscreen y el modo ventana. Veamos el ejemplo que se encuentra en la carpeta capitulo_02\003_cambiar_ventana_fullscreen.


Al principio del programa agregamos una constante y una variable para controlar el pasaje entre el modo fullscreen y el modo ventana:


# Control del modo ventana o fullscreen.
RESOLUTION = (640, 360)
isFullscreen = False

# Poner el modo de video en ventana e indicar la resolución.
screen = pygame.display.set_mode(RESOLUTION)
# Poner el título de la ventana.
pygame.display.set_caption("Mi Juego")

La constante RESOLUTION es una tupla que contiene los valores del tamaño de la ventana o resolución de la pantalla. La variable isFullScreen valdrá True cuando se ejecute en modo fullscreen, y valdrá False cuando se ejecute en modo ventana. Al comienzo se empieza en modo ventana, por lo cual esta variable vale False.


Luego, en el game loop, en la parte del proceso de eventos, chequeamos si el jugador pulsa la tecla [F]. Si lo hace, se cambia la variable isFullscreen entre los valores True y False, y a continuación se vuelve a establecer el modo de video correspondiente.


# Si se pulsa la tecla [F], se cambia entre ventana y fullscreen.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_f:
     		isFullscreen = not isFullscreen
          	if isFullscreen:	
screen = pygame.display.set_mode(RESOLUTION, 
pygame.FULLSCREEN)
else:
           	screen = pygame.display.set_mode(RESOLUTION)

Nota: Cuando una línea no entra en el código listado en el libro, se baja para que quede legible. Solo recuerda que en el programa esto no se puede hacer. Las líneas deben de ser continuas. De lo contrario el programa dará error.


Con esto hemos terminado con la programación de este capítulo. Veamos a continuación un par de conceptos que necesitamos saber y que hemos pasado un poco por alto.


Blit


En el programa hemos utilizado esta sentencia para mostrar la imagen de background:


# Actualizar la pantalla.
screen.blit(imgBackground, (0, 0))
pygame.display.flip()

La función o método blit() lo que hace es, aplicada a una imagen o superficie, dibuja la imagen que se le pasa como parámetro en las coordenadas indicadas. A la función blit() se le pasa la imagen a dibujar y las coordenadas de la esquina superior izquierda. En este caso estamos dibujando en la coordenada (0, 0) de la pantalla, porque la imagen a dibujar es del mismo tamaño que la ventana.


La operación de dibujar una imagen se denomina blitting. Blit es una abreviación de bit blit, que significa “binary block transfer” (o copia bit a bit). Es una técnica que se usa con la memoria para copiar un área rectangular de un lado a otro. Cuando decimos que copiamos una imagen, lo que estamos diciendo es que estamos haciendo blit a una nueva posición.

Esta operación de blit se encuentra disponible en la mayoría de las tarjetas gráficas.


Nota: Cuando una función se aplica a un objeto, o dicho de otra forma, un objeto tiene adentro una función, a esa la función se le denomina método. Como la diferencia entre función y método depende de si se encuentra dentro de un objeto o no, y ambas son funciones, generalmente se utiliza la palabra función.


Double Buffering


Para la computadora, desplegar gráficos en la pantalla es un proceso lento. Por este motivo, se dibuja en una superficie que se encuentra en la memoria (porque es mucho más rápido manipular la memoria) y luego, al final, se vuelca a la pantalla.


Con Pygame debemos utilizar la función pygame.display.flip() para copiar la imagen de background al display (a la pantalla). Al proceso de dibujar en una imagen de fondo y luego volcarla a la pantalla se le denomina double buffering. Esta técnica permite una mejor calidad de animación, evitando el parpadeo (no usar double buffer produce un parpadeo de la pantalla). Los videojuegos siempre utilizan esta técnica para dibujar y Pygame ya lo hace por nosotros.


Nota: La palabra buffer significa que es una parte de la memoria utilizada para almacenar temporalmente, en este caso, la imagen de la pantalla.



Figura 2-5: Cómo funciona el double buffer. Paso 1.



En la figura 2-5 vemos la primera etapa del double buffer, en la cual se dibuja en el back buffer cada uno de los elementos del juego. En este caso se dibuja el fondo, luego los enemigos y por último el jugador. En este momento tenemos armada la imagen en el buffer, pero no está visible en la pantalla.


Figura 2-6: Cómo funciona el double buffer. Paso 2.



En la figura 2-6 vemos cómo al llamar a la función pygame.display.flip(), el contenido del back buffer es volcado a la pantalla y en ese momento es que se ve realmente en la pantalla. El double buffer entonces implica dibujar al back buffer y al final volcar el back buffer al display. Por suerte, Pygame hace todo fácil para nosotros y lo único que haremos es utilizar la función blit para dibujar en screen, que representa el back buffer, y al final usamos pygame.display.flip() para hacer visible el frame actual.


Con esto, hemos terminado la base para comenzar a construir nuestro primer videojuego, cosa que haremos en los próximos capítulos.


 
 
 

Comments


bottom of page