Mostrando entradas con la etiqueta Juego. Mostrar todas las entradas
Mostrando entradas con la etiqueta Juego. Mostrar todas las entradas

miércoles, 9 de julio de 2025

Gráficos. Python

PyGame. Eventos de ratón


Los eventos de ratón afectan a los botones, la rueda y el desplazamiento del ratón por la superficie. Los dos primeros son similares a los de teclado (presionar - soltar), pero el de desplazamiento o movimiento ofrece otras posibilidades.


Veamos en primer lugar los que afectan a los botones (1 - 2 - 3) y a la rueda (4 - 5) y a su estado (MOUSEBUTTONDOWN vs MOUSEBUTTOMUP)

elif event.type == pygame.MOUSEBUTTONDOWN:
            print("Botón del mouse presionado:", event.button)
            if event.button == 1:
                print ("Se ha pulsado el botón izquierdo del ratón (botón ",event.button,")")
            elif event.button == 2:
                print ("Se ha pulsado el botón central del ratón (botón ",event.button,")")
            elif event.button == 3:
                print ("Se ha pulsado el botón derecho del ratón (botón ",event.button,")")
            elif event.button == 4:
           print ("Se ha accionado la rueda del botón hacia delante (evento ratón ",event.button,")") 
            elif event.button == 5:
              print ("Se ha accionado la rueda del botón hacia atrás (evento ratón ",event.button,")") 

Una vez capturado el evento  MOUSEBUTTONDOWN MOUSEBUTTONUP (v.g. event.type == pygame.MOUSEBUTTONDOWN), podemos identificar el botón pulsado (event.button) y, tomando como referencia la equivalencia entre identificador numéricos (v.g. if event.button == 1:) ...

  • 1 para el botón izquierdo
  • 2 para el central
  • 3 para el derecho
  • 4 para el avance de la rueda
  • y 5 para el retroceso
...  asociarlo a alguna acción o conjunto de acciones (en el ejemplo print ("Se ha pulsado el botón izquierdo del ratón (botón ",event.button,")") ).

Las posibilidades de trabajo con este procedimiento es similar al que tenemos con la identificación de los eventos de teclado (aunque es dudoso que podemos desarrollar procedimientos complejos, a modo de paneles de control), pero las que nos ofrece la captura del desplazamiento del ratón (pygame.MOUSEMOTION:)...

if event.type == pygame.MOUSEMOTION:
    print(f'Ratón movido a {event.pos} ')

...  nos abren un amplio mundo de opciones (antes sólo print(f'Ratón movido a {event.pos} ')) una vez que capturamos los valores numéricos de las posiciones cartesianas x - y, como es el caso del [script que sigue]...

import pygame

# Inicializar Pygame

pygame.init() 

# Configurar la pantalla

window_size = ( 800 , 600 ) 

screen = pygame.display.set_mode(window_size) 

pygame.display.set_caption( 'Ejemplo de posición del mouse' ) 

# Configurar la fuente para mostrar texto

font = pygame.font.Font( None , 36 ) 

# Bucle principal (game loop)

running = True 

while running:

#Captura todos los eventos que suceden en la ventana

    for event in pygame.event.get():

#Captura evento de ventana (QUIT) para cerrarla

        if event.type == pygame.QUIT:

            running = False

# Rellena la pantalla con blanco (RGB 255,255,255)

    screen.fill(( 255 , 255 , 255 ))

# Obtiene la posición actual del mouse...

    x, y = pygame.mouse.get_pos()

# ... y la presenta en el texto en color rojo (RGB 250,0,0)

    text = font.render( f'Posición del puntero del ratón: {x} - {y}' , True , ( 250 , 0 , 0 ))

# Redibuja el texto en la pantalla...

    screen.blit(text, ( 20 , 20 ))

#... y la actualiza

    pygame.display.flip()

# Salir de Pygame

pygame.quit() 

... que es sólo un ejercicio sin pretensiones de utilidad práctica, pero que nos permite pensar en posibilidades de aplicación como mapas, cronogramas, gráficos interactivos...

sábado, 19 de abril de 2025

MAV. Python


PyGame




Objeto sonido


Además de imágenes también necesitamos incluir sonidos en nuestras recursos para que puedan ser considerados MAV. Los juegos hacen uso continuado de ambos, así que PyGame no sería un buen recurso si no contara con procedimientos que permitieran el uso de sonidos.



Como lo primero que tenemos que tener es audios, qué mejor que un programa (gratuito) de edición y grabación de audio como es Audacity, o si se prefiere, más especializado de trabajo con grabaciones de voz como es PRAAT (sobre ambos, consultar enlaces  en Contenidos), así que, para desarrollar esta entrada voy a grabar un audio con la palabra taza. Así seguimos trabajando con el script en el que incorporamos la imagen de una taza.

Lo primero que tenemos que hacer para trabajar con audios en PyGame es inicializar los recursos de audio (pygame.mixer.init()), cosa que corresponde hacer en la sección 1ª del script, a continuación de la inicialización de pygame (pygame.init())

Siguiendo en esta misma sección, después de finalizar el proceso de carga de la imagen, procedemos a cargar y ajustar el sonido.
  • Cargándolo en memoria (pygame.mixer.music.load("assets/taza.mp3")) mediante la función music.load() del objeto mixer.
  • Estableciendo el modo de reproducción mediante la función music.play(). Si pasamos como parámetro 0 se reproduce una vez, pero si pasamos como parámetro -1 se reproduce en bucle. En este caso pygame.mixer.music.play(0)
  • Y para finalizar indicamos el volumen deseado mediante la función set_volumen() (vg. pygame.mixer.music.set_volume(0.5))
Y de este modo tan sencillo ya disponemos de recursos para crear una presentación basada en PyGame que utilice imágenes y sonidos. Cierto que nos falta saber cómo incorporar textos, cosa que veremos más adelante, pero podemos simular su uso capturándolos como imágenes desde la pantalla. No es muy elegante como solución, pero sí efectiva. Además ya te adelanto que el trabajo con textos en PyGame no es precisamente sencillo y (considero) tampoco es que brille por su utilidad.

En cualquier caso, desde este enlace puedes descargar el script explicado en la entrada. Y [desde este otro el audio], que también debes incluir en la carpeta assets. al igual que las imágenes.

MAV. Python


PyGame



Objeto imagen

Para incluir una imagen en nuestra ventana lo primero que nos debemos plantear es qué función cumplirá dicha imagen, si como elemento de la aplicación o como escenario de la acción que se va a desarrollar en la ventana. 



Diferencio dos funciones básicas para una imagen: como elemento de la ventana y de la historia que en ella se cuenta y como imagen de fondo o escenario en el que se desarrolla la acción. Los problemas que nos vamos a encontrar no tienen soluciones muy diferentes, pero sí lo son conceptualmente. 
Pero lo primero que debemos resolver es la carga de la imagen en la ventana, cosa que hacemos gracias a la función image.load() (img_a = pygame.image.load('assets/taza.png'))

Cuando nuestro objetivo es usar la imagen como componente de la escena (los usos posibles son muchos) lo que nos interesa es acertar con la ubicación y con el tamaño. Ambos se resuelven teóricamente...
  • gracias al tamaño de la propia imagen, que conocemos mediante (Propiedades | Detalles) o al uso de un programa de edición de imágenes, que nos informan del tamaño de la imagen en pixeles.
  • ... y mediante la función blit(), que admite como parámetros una tupla con la posición xy de la esquina superior izquierda de la imagen (ventana.blit(taza,(100,50)) coloca la imagen taza en la posición x = 100, y = 50). Deberemos, esos sí, probar con diferentes valores x-y para lograr un posicionamiento que se ajuste a nuestros objetivos y gustos.
Pero ahora nos encontramos con dos problemas (que son en realidad el mismo) según que nuestro objetivo para la imagen sea uno (como elemento de la pantalla) u otro (como fondo de la pantalla o escenario de la acción): el tamaño de la imagen NO se ajusta a lo que deseamos; la imagen es muy pequeña o demasiado grande.

En ambos casos cabe la solución de modificar el tamaño original de la imagen mediante un programa de tratamiento de imágenes, y es posible que esta sea la mejor solución, pero no es necesario y tampoco es posiblemente suficiente según para qué objetivo (por ejemplo no lo es si vamos a hacer uso de la ventana a pantalla completa).

Lo que yo te propongo es hacer uso de una función disponible en PyGame que nos permite modificar el tamaño de la imagen (pygame.transform.scale()), función que recibe como primer parámetro la propia función que nos sirvió para cargar la imagen a la que se añade además una función de ajuste de la calidad de la imagen (convert()), y como segundo parámetro la tupla de tamaño de la imagen (img=pygame.transform.scale(pygame.image.load("assets/coas.jpg").convert(),(200,250)))

Pues bien, según el uso que vamos ha hacer de la imagen te propongo dos modos diferentes de emplear este conjunto de opciones, empezando por un uso de la imagen como objeto (vs. fondo)

En ambos casos primero deberemos crear la ventana siguiendo el [procedimiento ya conocido] (ventana = pygame.display.set_mode((ANCHO,ALTO))), incluyendo (obligatoriamente en este primer ejemplo, opcionalmente pero recomendable en el segundo) asignar un color de fondo a nuestra ventana (ventana.fill(BLANCO)).

Ahora expongo mi propuesta para un uso de la imagen como objeto de la ventana:
  • Primero accedo a los valores ancho y alto de la imagen (vg.  img_ancho = taza.get_width()) mediante las funciones get_width() get_height()
  • y después utilizo estos valores para redimensionar la imagen a mi gusto (taza_bis = pygame.transform.scale(taza, (img_ancho//2, img_alto//2))), 
  • ... siendo esta imagen redimensionada la que implemento en la ventana en la posición que deseo (ventana.blit(taza_bis,(100,100)))
En este enlace te dejo acceso al script que desarrolla mi propuesta. La imagen la puedes descargar desde aquí, aunque deberás ubicarla dentro de una carpeta llamada assets, ubicada dentro del directorio donde guardes el script.

La segunda forma de uso de la imagen es como fondo de ventana. En este caso no es necesario dar color a la ventana, aunque se puede hacer igualmente. Lo importante ahora es controlar el tamaño original de la imagen, ya que debe existir coincidencia entre éste y el de la propia ventana. Esto lo podemos logar invirtiendo el procedimiento que seguimos antes, de modo que, conocido el tamaño de la imagen mediante las funciones get_width()get_height(), y asignándolas a sendas constantes (ANCHO y ALTO), las utilicemos como valores que definen el tamaño de la ventana.

El problema es que esto puede dar lugar a extraños y poco usuales tamaños de ventana, por lo que como solución no termina de convencer. Y lo malo es que si no existe coincidencia entre ventana e imagen, o bien se va a ver que la imagen no ocupa toda la ventana


... o sólo se verá una parte de la imagen como fondo. Y esto se acentúa si usamos el modo pantalla completa (FULLSCREEN).

Evidentemente, como dije antes, nos queda la opción de reajustar el tamaño de la imagen con un programa de edición de imágenes, y no debemos descartar hacerlo así, especialmente si no vamos a usar el modo FULLSCREEN; pero también podemos usar la función transform.scale(), ahora de un modo un tanto diferente (fondo = pygame.transform.scale(pygame.image.load("assets/espacio.jpg").convert(),(ANCHO,ALTO))), que usa como segundo parámetro la tupla formada por las mismas constantes de tamaño que empleamos para dimensionar la ventana.

Aquí el tema de la posición de la imagen (ventana.blit(fondo,(0,0))) solo tiene una solución: en la coordenada (0,0).

También desde aquí puedes descargar el script de uso de imagen como fondo. Y [aquí tienes la imagen] usada como fondo. Debes proceder del mismo modo que con la imagen de la taza.

miércoles, 16 de abril de 2025

Gráficos. Python

PyGame. Objeto ventana


Todo en PyGame son clases, objetos, atributos, métodos... dado que en Python, pero sobre todo en PyGame el paradigma de programación dominante es el llamado Programación Orientada a Objetos (POO)... incluso cuando nosotros estemos trabajando desde la óptica de otro paradigma, como el de programación lineal. De ahí que hablemos del objeto ventana, por cierto, uno de los fundamentales (imprescindible, diríamos) de todo script PyGame. Así que está más que justificado iniciar por ventana este recorrido por los objetos de esta librería.


El programa más simple que podemos escribir usando PyGame debe contener necesariamente una ventana, aunque de momento no sirva para nada más que demostrar que el programa existe y funciona. Este sería un ejemplo de lo que acabo de decir:

import pygame
pygame.init()
pygame.display.set_mode((800,600))
pygame.time.delay(2000)
pygame.quit()

Este script únicamente muestra en nuestro monitor una pantalla de 800 x 600 pilxeles de color negro durante 2 segundos. Después se cierra. No es mucha cosa, pero es el principio necesario. Además nos muestra tres opciones de desarrollo: el tamaño de la pantalla, el color de fondo y el manejo del tiempo de visualización.
  • El tamaño de la pantalla depende de la tupla que recibe como parámetro el método (o función) set_mode() (recuerda usar doble paréntesis) del objeto display, así que lo podemos modificar para que se ajuste lo mejor posible a nuestro monitor, llegando incluso a utilizarlo a pantalla completa. Tema interesante sobre el que volveremos, por cierto.
  • Dado que se usa un color por defecto, el manejo de esta opción no queda expresado en este primer script,  pero enseguida comprobaremos la necesidad de presencia.
  • Finalmente, el control del tiempo de exposición de nuestra ventana mediante el método delay() del objeto time es una licencia que nos tomamos ahora para facilitar el visionado del funcionamiento del script, por lo que no será un método que veamos necesariamente en otros script, pero que tiene su interés, especialmente para un uso de PyGame un tanto diferente del habitual.
Con todo, incluso para nuestros sencillo fines, este script es excesivamente sencillo, así que vamos a trabajarlo un poco más... empezando por dar color a esa ventana, aunque sea color blanco...

import pygame
pygame.init()
ventana = pygame.display.set_mode((800,600))
ventana.fill((255,255,255))
pygame.display.update()
pygame.time.delay(2000)
pygame.quit()

Como puedes ver he necesitado dos líneas de código para animar un poco esa primera ventana:
  • Usando el método fill() que recibe como parámetro una tupla con tres valores numéricos (derivada del sistema de codificación del color en formato RGB)
Esa tupla la podemos sustituir por una constante

BLANCO = (255,255,255) -> ventana.fill(BLANCO)

  • Y el método update(), encargado de actualizar los valores de la pantalla.
La primera instrucción se posiciona en la sección 1 y la segunda en la sección 2.

Existe otro modo de tratar el trabajo con el color de la ventana que consiste en considerarlo como una superficie superpuesta a la propia ventana a modo de fondo o background. Esa es la propuesta de Fernando Sansberro y la que adopté en [el script] que utilicé como ejemplo de estructura de script. Reproduzco por motivos didácticos:

#Superficie del fondo de pantalla
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((0, 0, 255))

La última de las instrucciones es la única realmente imprescindible y es la que ya conocemos por la anterior formulación. El resto nos lleva al tema del uso de una imagen como fondo de pantalla, cuestión esta que aun no está a nuestro alcance, aunque lo estará en breve. Ahora prefiero que nos centremos en la definición del tamaño de la ventana.

Mientras que estas instrucciones se ubican dentro de la sección 1, en la sección 2 deberemos actualizar la imagen de fondo de la pantalla (screen.blit(imgBackground, (0, 0))), además de redibujar ésta (pygame.display.flip())

Pero realmente no supone ninguna dificultad establecer las dimensiones de ventana que mejor se ajuste a nuestro monitor y al objetivo de nuestro script; es suficiente con establecerlo directamente como valores numéricos en la función set_move() o, en su defecto, indicarlo por medio de una variable...

size = (800,600)

 ventana = pygame.display.set_mode(size)

... o mediante dos constantes

ANCHO = 800

ALTO = 600

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

... pudiendo modificar esos valores numéricos sin necesidad de modificar la instrucción que establece la propia pantalla mediante set_mode(). Únicamente queda por plantear una situación especial que no se resuelve modificando esos valores: cuando deseamos trabajar a pantalla completa (fullscreen). En este caso necesitamos modificar la instrucción de base añadiendo un segundo parámetro a set_mode(): pygame.FULLSCREEN

V.g ventana = pygame.display.set_mode(size, pygame.FULLSCREEN)

Dos observaciones son necesarias en estos momentos:

  • Observación 1: aunque en los equipos modernos no es normal que falle la tarjeta gráfica al usar el modo fullscreen, si puede suceder en equipos antiguos, por lo que debemos saber que las resoluciones que aceptan ese modo de pantalla son las siguientes: 640 x 480, 800 x 600, 1024 x 768 y 1920 x 1080. Se recomienda usar cualquiera de los dos primeros como tamaños de ventana por ser las medidas de uso más frecuente.
  • Observación 2: El uso de la pantalla a tamaño completo tiene repercusiones sobre los objetos contenidos en ella y sobre la imagen de fondo, por lo que no te recomiendo que lo uses en estos momentos, ya que aun no nos corresponde entrar en estas cuestiones y dar solución a los problemas que puedan surgir. Por el momento es suficiente con que sepas que es posible trabajar con diferentes tamaños de ventana, realizar cambios de tamaño y trabajar a pantalla completa. En breve aprenderemos a sacar rendimiento de estas posibilidades.

domingo, 13 de abril de 2025

Gráficos. Python

PyGame. Tercera sección.


Esta entrada tiene poco que contar, pero es necesaria para completar el análisis de la estructura básica de un script pygame.


Sencilla, fácil de entender, pero imprescindible; la tercera y última sección de un script pygame se escribe fuera del game loop, y en último lugar, incluyendo cuando el script carece de game loop, situación extraordinaria, pero posible, como vimos en la [entrada anterior].

Esto es debido a que con la instrucción pygame.quit() o simplemente la función quit() (ya sabemos que eso depende del modo en que importemos pygame), lo que estamos haciendo es liberar la memoria de todos los recursos asociados al lenguaje Python que hayamos solicitado al sistema, incluyendo, evidentemente, la biblioteca PyGame.

Según nuestro script modelo, esta tercera sección se concreta como sigue:

#Sección 3: Cerrar y liberar recursos ---------------------------

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

De este modo evitamos sobrecargar la memoria de nuestro ordenador. Con independencia de que estemos sobrados de recursos, es una buena práctica que además genera un efecto acorde con lo esperado en el funcionamiento de un script: su cierre.

Con esta entrada podemos dar por finalizada la explicación de la estructura básica de un script (en realidad de un programa-juego) creado con PyGame, pero nos quedan aun muchas cosas por aprender, incluyendo algunas que supondrán volver a hablar de alguna de estas tres secciones.

Gráficos. Python

PyGame. Segunda sección. Game loop.


Curiosamente el game loop, que es el corazón del script y el componente fundamental de su segunda sección, es posible que no esté presente, o no del modo en que se espera, en determinados usos de PyGame. Usos poco frecuentes y posiblemente no especialmente ajustados a las posibilidades de esta biblioteca, pero no por ello menos posibles.



La sección 2 se asocia normalmente al bucle infinito del juego (game loop) y es, a su vez, la parte más compleja del script PyGame, estando conformado, normalmente por las siguientes secciones:
  • Manejo de eventos
  • Actualización de pantalla
  • Dibujar nuevo contenido
El game loop se suele formular mediante el bucle while (while not salir:), ya que este bucle se ejecuta mientras se cumpla determinada condición, la cual suele establecerse a priori (salir = False). 

En este nuestro ejemplo se formula el game loop y su bucle while mediante una doble negación, lo cual no suele ser la norma, la cual simplifica esta formulación que suele hacerse en positivo (vg):
  • running = True
  • while running:
La primera parte del game loop es el manejo de los eventos que se producen en la pantalla, los cuales pueden ser objeto de un tratamiento muy simple o de mucha complejidad. En el script que nos sirve de referencia se manejan eventos del modo más sencillo posible, y está bien que así sea para empezar, pero en posteriores ejemplos veremos algunas de las múltiples posibilidades que presenta el manejo de eventos. De momento nos servirá saber que se requieren un segundo bucle (en esta caso un bucle for (for event in pygame.event.get():) que se complementa con estructuras condicionales (vg. if event.type == pygame.QUIT:), las cuales capturan los eventos y, en función de ellos, se toman decisiones (en este caso salir = True, que equivale a salir del game loop).

Además del acceso a los eventos de pantalla, el game loop también incluye otras dos partes, ambas fuera del bucle for de captura de eventos: la actualización de la pantalla (screen.blit(imgBackground, (0, 0))) y dibujar en la pantalla lo creado previamente (pygame.display.flip()). Estas instrucciones son obligadas y en ese mismo orden. En caso de ausencia o de inversión del orden se altera el correcto funcionamiento del script.

Curiosamente ambas afectan más al funcionamiento del script que el propio game loop. Lo digo en el sentido de que su ausencia invalida el script, pero no la ausencia del game loop, aunque ésta impide la creación de un juego como tal, pero no el uso de PyGame para otras utilidades. 

Para ejemplificar la posibilidad de crear un script PyGame sin game loop pondré un ejemplo muy sencillo aunque : la sucesión de pantallas de diferentes colores. Para ello repetiré una secuencia de cuatro instrucciones tres veces, mostrando así tres pantallas de tres colores diferentes. Y todo ello sin utilizar ni el bucle while (game loop) ni el bucle for (asociado en game loop a la captura de eventos. 

El script completo está accesible desde [este enlace], pero paso a explicar la composición de estas estructuras que, en esta ocasión se repiten tres veces.

imgBackground.fill((0, 0, 255))
screen.blit(imgBackground, (0, 0))
pygame.display.flip()
pygame.time.delay(2000)

La primera instrucción es, si recuerdas, la tercera del bloque de tres instrucciones situadas en la sección 1ª del script modelo dedicadas a establecer el fondo de pantalla. La segunda y tercera son las mismas que ubicamos dentro del game loop para actualizar la pantalla y la cuarta nos permite establecer un tiempo de espera que facilita apreciar el funcionamiento del script: en esta caso establecemos una demora de 2 segundos, usando para ello la función delay() asociada al objeto time de la biblioteca pygame.

Realmente este script no es más que un ejercicio que que demuestra que es posible trabajar con PyGame sin usar game loop, pero no tiene una utilidad inmediata. Para que sí la tenga necesitamos aprender aun unas cuantas cosas. Cuando lo hagamos y estemos en condiciones de demostrar lo que ahora adelanto, prometo que lo pondremos en práctica.

sábado, 12 de abril de 2025

MAV. Python


PyGame



Primera parte del script


Analizo a continuación el contenido típico de la primera sección de la estructura de un script.


Recordemos el contenido de esta sección en el [script que nos sirve de modelo]...

#Sección 1 ---------------------------------------------------

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


#Crear ventana y establecer tamaño
screen = pygame.display.set_mode((640,360))

#Poner título a la ventana
pygame.display.set_caption('Mi primer juego')

#Superficie del fondo de pantalla
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((0, 0, 255))

... aunque va a resultar de precisamente de modelo tiene bien poco. Lo digo tanto por lo que falta como por lo que hay y no es tan común que conste en esta sección. Empiezo por lo segundo, lo que falta.

En efecto, la primera sección de un script PyGame suele contener también la declaración e inicialización de las constantes y variables que es frecuente emplear y que, por lo común, se refieren a las constantes de tamaño de la ventana, en su caso las constantes de los colores y posiblemente también los valores iniciales de los parámetros x e y. Lo explico.

Inmediatamente después de inicializar PyGame (pygame.init()) creamos una ventana asociada a la variables screen (screen = pygame.display.set_mode((640,360))) mediante la función set_mode() que recibe como parámetro una tupla con dos valores numéricos que se corresponden respectivamente con el ancho y el alto de la ventana.

Aunque esta forma de plantear la instrucción es válida, es posible mejorarla utilizando una tupla previamente declarada (vg. size = (640,360)) o bien creamos dos constantes (ANCHO = 640 | ALTO = 360). En cualquiera de los casos, esa variable o estas constantes deberán figurar en la sección 1ª del script.

De modo similar, más abajo generamos un fondo de ventana (imgBackground.fill((0, 0, 255))) empleando también una tupla con un código RGB. En este caso es común encontrar en la sección 1ª un conjunto de constantes que se asocian a las tuplas los correspondientes códigos RGB.

Aplicando ambas opciones nuestra sección 1ª se mostraría como sigue:

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

#Inicializar constantes
ANCHO = 640
ALTO = 360

BLANCO = (255,255,255)
NEGRO = (0,0,0)
ROJO = (255,0,0)
VERDE = (0,255,0)
AZUL = (0,0,255)

#Crear ventana y establecer tamaño
screen = pygame.display.set_mode((ANCHO,ALTO))

#Poner título a la ventana
pygame.display.set_caption('Mi primer juego')

#Superficie del fondo de pantalla
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((AZUL))

Se supone que en script complejos y cuando nos interesa reutilizar código, el uso de constantes y variables facilita el trabajo, ya que evita tener que modificar los datos (en este caso numéricos) en cada una de las instrucciones en las que son requeridos. Por si te es de utilidad, te dejo [enlace a un script] que implica el uso de esta forma de proceder.

Visto hasta aquí lo que puede faltar en la sección 1ª, vamos a ver ahora lo que no suele estar, aunque está bien que éste. Me refiero a las instrucciones que establecen las características del fondo de pantalla.

La primera de estas instrucciones (mgBackground = pygame.Surface(screen.get_size())) crea una superficie mediante la función Surface() que recibe como parámetro la misma dimensión que tiene la ventana, a la cual accedemos mediante la función screen.get_size().

La instrucción imgBackground = imgBackground.convert() convierte el formato de la imagen precedente al mismo que tiene PyGame (esto es, al formato de la pantalla), evitando así posibles demoras en el tratamiento de las imágenes.

Finalmente, la instrucción imgBackground.fill((AZUL)) se encarga de llenar la imagen del color que hemos especificado en la constante AZUL, esto es el que resulta de la tupla (0,0,255), que es el color RGB azul.

Es precisamente esta última instrucción, aunque modificada, la única de las tres que suele figurar como parte de la sección 1 (screen.fill((AZUL))) resultando [este script] como posible realización de estos cambios. Obsérvese que también se ha simplificado el contenido de la sección 2.


MAV. Python


PyGame





Estructura básica de un juego

Seguiré en este recorrido por la biblioteca PyGame a [Fernando Sansberro] y más concretamente a su documento [Hacete tu Videojuego], aunque se incluirán contenidos de otros autores cuando lo considere necesario. En todo caso, el objetivo de este conjunto de entradas es aprender lo suficiente de PyGame para que nos permita generar recursos para la intervención y la evaluación, incluyendo juegos, obviamente, pero no como finalidad principal, por interesante que éstos puedan ser.


Para empezar vamos a hacer un breve recorrido por la estructura básica de un programa PyGame, aunque decir esto sea doblemente engañoso..
  • Esta estructura no se limita a PyGame, sino que es usada, en lo esencial, en toda construcción de un juego.
  • Podemos trabajar en PyGame usando otras estructuras más simples.
... pero a la vez es fundamentalmente cierto: incluyendo modificaciones en función de la complejidad del proyecto, el esquema básico de la mayoría de los script Python-Pygame se ajustan a este esquema.

En ella se diferencian tres partes fundamentales:
  • En la primera se inicializa PyGame y se cargan los recursos que se vayan a emplear en el programa.
  • En la segunda se desarrolla un bucle infinito de juego (Game loop), que a su vez se descompone en varias fases (que describiré en su momento)
  • Y en la tercera se cierra el juego, liberando todos los recursos que se hayan empleado.
Para ejemplificar esta estructura expongo a continuación el script que desarrolla [Fernando Sansberro] y que he modificado (muy levemente) para (pretendo) mejorar su comprensión. Sobre esta base realizaré las explicaciones que he considerado necesarias. Este es el [enlace al script]

# -*-   coding: utf-8   -*-
#-------------------------------------------------------------
# Primer script. Ejemplo de game loop
#Autor: Fernando Sansberro - Batovi Games.
#Replica: Javier Alonso.
#Proyecto : Hacete tu Videojuego
#Licencia: Creative Commons. BY-NC-SA
#-------------------------------------------------------------
#Uno. Estructura básica de un script PyGame
#--------------------------------------------------------------

#Sección 1 ---------------------------------------------------

#Importar e inicializar pygame

import pygame
pygame.init()

#Crear ventana y establecer tamaño
screen = pygame.display.set_mode((640,360))

#Poner título a la ventana
pygame.display.set_caption('Mi primer juego')

#Superficie del fondo de pantalla (background)
imgBackground = pygame.Surface(screen.get_size())
imgBackground = imgBackground.convert()
imgBackground.fill((0, 0, 255))

#Sección 2: Game loop----------------------------------

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

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

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

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

#Sección 3: Cerrar y liberar recursos------------------------

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

Dejando a parte (no por innecesarias, que no lo son) las primeras líneas en las que se explica el script, iniciamos éste con su primera parte o fase de inicialización, que en este caso se concreta como sigue:

import pygame
pygame.init()

Instrucciones fundamentales para el funcionamiento del script y que deben figurar (de este modo o con las modificaciones que deriven de las preferencias del usuario) en todo programa PyGame.

Otros autores inicializan PyGame como from pygame import * haciendo innecesario llamar a pygame en las instrucciones que en nuestro ejemplo sí es requerido (vg. pygame.init() -> init()). Aquí te dejo [acceso a un script] reducido en el que al emplear la fórmula from pygame import * no es necesario llamar a pygame en cada instrucción o función.

El resto del código requiere su propia explicación, cosa que haré en entradas sucesivas, para centrarme en ésta en la exposición de la organización general del código.

El script se inicia con lo que llamo sección 1 y que contiene, además de la carga de la biblioteca y la inicialización de Pygame, la creación de la ventana y otros contenidos relacionados con ella. En su momento veremos que cuando el script es complejo, en esta sección también se incluye la declaración de constantes y variables.

Curiosamente la segunda parte, la más característica y definitoria de un juego, el game loop, no es obligatoria cuando el uso que vamos a dar a esta biblioteca no es para crear un juego, pero esta situación es excepcional. En la inmensa mayoría de las aplicaciones reales de PyGame es obligado crear un bucle infinito (game loop), que se estructura a su vez en al menos tres partes. Ahora sólo las nombro, ya que en una entrada posterior las explicaré con detalle. Estas partes son:
  • La captura de eventos
  • El dibujo de elementos en la pantalla (formas, imágenes, textos...)
  • Y la actualización de la pantalla.
Para finalizar, una vez que se cierra el game loop, es conveniente salir del juego cerrando el acceso a los recursos que se emplearon para generarlo. De esto se encarga la tercera y última sección del juego, generalmente haciendo uso de la función pygame.exit() o simplemente exit(), según el modo en que se accedió (cargó) la biblioteca PyGame, como ya expliqué antes.