Mostrando entradas con la etiqueta PyGame. Mostrar todas las entradas
Mostrando entradas con la etiqueta PyGame. 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...

Gráficos. Python

PyGame. Eventos de teclado


Los eventos de teclado permiten identificar las teclas sobre las que ha pulsado el usuario. A partir de ahí podemos transformar este conocimiento en una forma de interacción entre el usuario y el programa.


Vamos a ver en esta entrada las formas en las que podemos capturar estos eventos. Algunas de ellas ya son conocidas, aunque no nos detuvimos especialmente en explicarlas. Por ejemplo, el modo en el que controlamos la ruptura del game loop:

running = True
while running:
    for event in pygame.event.get():
#Capturamos el evento ventana para cerrar el bucle
        if event.type == pygame.QUIT:
            running = False

Después de capturar los eventos mediante un for  con la función event.get() (for event in pygame.event.get():), controlamos el evento pygame.QUIT para generar la ruptura del bucle, modificando el valor de la variable que lo controla (running = False) mediante el condicional (if event.type == pygame.QUIT:).

Pero en sentido estricto (el anterior es un evento de ventana), los eventos de teclado (pygame.KEYUP pygame.KEYDOWN ) se refieren al control de qué tecla ha sido pulsada o liberada, identificándola por su "nombre" ( if event.key == pygame.K_f:)...

elif event.type == pygame.KEYUP:
            if event.key == pygame.K_f:
                print ("Hemos presionado la tecla f")

... o por su código o número (if event.key == 97:)

elif event.type == pygame.KEYDOWN:
            if event.key == 97:
                print("Tecla presionada la tecla A (", event.key,")")

Otra cosa es qué hagamos con ese control. De momento nos sirve únicamente para identificar la tecla, a fin de centrar la explicación en el propio evento. En posteriores desarrollos veremos posibles aplicaciones; por ahora apuntar únicamente que, gracias al control de los eventos de teclado podríamos construir teclados orientados a funciones específicas, a modo de paneles de control. Este ya es un tema que requiere algo de bricolaje informático, no sólo programación.

Gráficos. Python

PyGame. Eventos


Dentro de la ventana del juego (o de la pantalla, si se prefiere) se producen eventos que resultan de la acción del usuario sobre los elementos que sirven de interfaz, como son el teclado y el ratón.


En PyGame, la función pygame.event.get() devuelve una lista de todos los eventos que suceden en pantalla, que son los siguientes:

- pygame.QUIT -> Cierre de ventana (pulsando la [X] de la ventana)

Eventos de teclado:

- pygame.KEYDOWN -> Cuando se presiona una tecla.
- pygame.KEYUP -> Cuando se suelta una tecla.

Eventos de ratón:

- pygame.MOUSEBUTTONDOWN -> Cuando se presiona un botón del ratón.
- pygame.MOUSEBUTTOMUP -> Cuando se suelta un botón del ratón.
- pygame.MOUSEMOTION -> Cuando el ratón se mueve.

Eventos de joystick:

- pygame.JOYAXISMOTION -> Cuando se mueve un eje del joystick.
- pygame.JOYBUTTONDOWN -> Cuando se presiona un botón del joystick.
- pygame.JOYBUTTONUP -> Cuando se suelta un botón del joystick.

Para mostrar en consola los eventos usamos la función print(event). Algunos de ellos son los siguientes:

Algunos eventos de ventana:

<Event(4352-AudioDeviceAdded {'which': 0, 'iscapture': 0})>
<Event(4352-AudioDeviceAdded {'which': 0, 'iscapture': 1})>
<Event(32774-WindowShown {'window': None})>
<Event(32768-ActiveEvent {'gain': 1, 'state': 2})>
<Event(32785-WindowFocusGained {'window': None})>
<Event(770-TextEditing {'text': '', 'start': 0, 'length': 0, 'window': None})>
<Event(32783-WindowEnter {'window': None})>

Algunos eventos de ratón:

<Event(1024-MouseMotion {'pos': (605, 211), 'rel': (0, 0), 'buttons': (0, 0, 0), 'touch': False, 'window': None})>
<Event(1024-MouseMotion {'pos': (615, 207), 'rel': (10, -4), 'buttons': (0, 0, 0), 'touch': False, 'window': None})>

Algunos eventos de teclado:

<Event(768-KeyDown {'unicode': '1', 'key': 49, 'mod': 0, 'scancode': 30, 'window': None})>
<Event(771-TextInput {'text': '1', 'window': None})>
<Event(769-KeyUp {'unicode': '1', 'key': 49, 'mod': 0, 'scancode': 30, 'window': None})>
<Event(768-KeyDown {'unicode': '2', 'key': 50, 'mod': 0, 'scancode': 31, 'window': None})>
<Event(771-TextInput {'text': '2', 'window': None})>
<Event(769-KeyUp {'unicode': '2', 'key': 50, 'mod': 0, 'scancode': 31, 'window': None})>
<Event(768-KeyDown {'unicode': '3', 'key': 51, 'mod': 0, 'scancode': 32, 'window': None})>

Lo interesante de los eventos es que su control mediante código nos permiten desarrollar interacciones entre el usuario y el programa. Algunos ejemplos de formas de uso serán tratadas en posteriores entradas.

domingo, 20 de abril de 2025

Comprensión

Evaluación

Comprensión oral. ITPA




También llamada comprensión auditiva, es la capacidad para entender lo que se dice y constituye una de las competencias lingüísticas básicas en la que intervienen procesos lingüísticos, cognitivos, perceptivos y también actitudinales que requiere la participación activa del oyente. Además, la comprensión oral está correlacionada con la comprensión lectora, aunque son dos competencias diferentes que se deben trabajar de forma relacionada pero específica.


Los procesos de comprensión auditiva se han entendido en la literatura científica desde dos perspectivas: como procesamiento sintético (bottom-up), que implica todos los procesos implicados en el lenguaje, y como procesamiento analítico (top down), que incluye el conocimiento general del mundo que tiene el oyente. Este mismo planteamiento se aplica también a la comprensión lectora y al igual que en ella, también aquí se puede entender que ambos enfoques en realidad son compatibles, como defiende el modelo interactivo.

En la práctica pedagógica, la comprensión auditiva se plantea en la etapa de Educación infantil con mayor o menor interés y acierto, pero al pasar a la etapa de E. Primaria generalmente sólo se mantiene como objetivo del proceso de enseñanza-aprendizaje en el área de Lengua extranjera, pero no en el de lengua castellana y literatura.

Tampoco en los procesos de evaluación psicopedagógica se presta especial atención a la evaluación de esta capacidad, aunque retazos de ella se mantienen en pruebas específicas de comprensión léxica (vocabulario) y gramatical (estructuras gramaticales). También puede emplearse como parte (muy limitada) de la evaluación de la comprensión lectora (véase PROLEC-R, subtest primeros ítem de Comprensión de oraciones y subtest Comprensión oral), como recurso para descartar dificultades específicas y/o relacionadas con las capacidades generales (CI).

Aun se comercializa un test que mantiene una prueba denominada específicamente como Comprensión auditiva. Me refiere al Test de Illinois (ITPA), de la [editorial TEA], aunque se trata mas de una especie de reminiscencia del pasado que de un producto actualizado (por si te interesa, actualmente y según catálogo on-line, tiene un precio nada barato de 373,08 €, IVA incluido. Aunque es un subtest de evidente interés, no vamos a tratar ahora sobre él, aunque bien podría ser objeto de atención dentro de este blog más adelante.

Lo que ahora te voy a plantear es una práctica más simple: la lectura de un cuento al alumnado por parte del docente, o simplemente contar (oralmente) un cuento. Esta práctica es común en la etapa de la E. Infantil y también en las familias (aunque posiblemente menos de lo deseado, especialmente por parte de éstas últimas). Cierto es que debería tener continuidad en la etapa de E. Primaria (sería conveniente, aunque modificando los contenidos), ya que en realidad parte de la práctica pedagógica, tan tradicional como habitual y necesaria, se basa en la comprensión oral del alumnado: me refiero a la práctica docente de lectura del contenidos del libro de texto o de la exposición oral del contenido conceptual a explicar: en resumen, lo que ambas prácticas requieren del alumnado se puede entender como comprensión auditiva (o comprensión oral), con toda la complejidad real que tiene esta competencia.

Para ilustrar esta práctica he optado por crear un script Python basado en la biblioteca PyGame que tiene como resultado un sencillo cuenta-cuentos. Se requiere disponer de la colección de imágenes necesarias (en secuencia, lo que da pie a trabajar también las secuencias temporales con las que la comprensión oral de textos narrativos también está relacionada) y de audios. Disponer de las primeras depende de la habilidad artística de cada cual (o de la habilidad que tenga para acceder a esas imágenes) y de los audios de las ganas que tenga de ponerse delante del micrófono del ordenador (por ejemplo) y usar un programa (gratuito y de fácil manejo) como Audacity

El script Python es muy simple como podrás comprobar, así que no tienes disculpa para usarlo para crear esos cuenta-cuentos que los peques esperan y que tú puedes puedes usar en el aula como herramienta complementaria de otras intervenciones, pero también en casa y, por qué no, como medio complementario en la interacción personal y directa con los peques. Seguro que le encanta que seas tú quien ha creado ese cuento para ellos; la percepción de los medios digitales que les proporciona este tipo de experiencias no debe ser subestimada.

En realidad el script es prácticamente el mismo que creé para explicar cómo hacer una presentación simple con PyGame [en esta entrada], así que las mismas explicaciones valen también para el actual. Quizás la única diferencia de importancia sea haber creado una segunda tupla (son = (4000,8000,15000,16000,18000,18000,9000)) con las direcciones de los audios como medio de ajustar la duración de la presentación (tmp = son[i]) de cada imagen a la duración del audio correspondiente (pygame.time.delay(tmp)).

Documentos. Y para finalizar, desde el enlace que sigue puede [descargar el archivocomprimido que contiene el script y los MAV (estos en la carpeta assets, cada uno en su subdirectorio, que es donde deben seguir estando cuando descomprimas el conjunto).

 

Evaluación. Soportes.

Presentación PyGame


Muy cierto, PyGame es una librería para desarrollar juegos 2-D, no para crear presentaciones, que para eso ya está [Python-pptx], pero no: con PyGame también podemos crear generadores sencillos de presentaciones (simples, al menos de momento); con sus limitaciones, pero también con unas funcionalidades que no son sencillas de implementar mediante Python-pptx.


Ahora que ya tenemos ciertos conocimientos sobre PyGame vamos a aprovechar para mostrar algunas posibilidades de uso que no son expuestas en la literatura sobre esta biblioteca (al menos, no en mis indagaciones) y que, aun con sus limitaciones, me ha parecido de interés. De paso demostramos que no todo en PyGame se basa en el bucle infinito... en un bucle sí, pero delimitado.

Una de esas posibles utilidades de PyGame consiste en utilizarlo para crear un "presentador" de contenidos audiovisuales. Cierto que en la acepción más 'pobre' pero estricta del término: unión de imágenes y sonidos en sucesión; vamos, lo que llamamos presentación básica de diapositivas. Cierto que limitada (reitero), pero no menos que la mayoría de las presentaciones que realizamos con LO-Impress (o Power point)... o las que aprendimos a crear con Python-pptx no hace mucho.

Aprovechando lo que [hemos aprendido recientemente sobre PyGame] (y siguiente) voy a desarrollar un script que nos permite visualizar una colección de imágenes que se muestran acompañadas de sonido. Se trata de un recurso para aprender palabras (vocabulario o léxico, si se prefieren expresiones más técnicas) y que perfectamente podría implementarse como sencillo cuenta-cuentos, o como la base para una actividad de comprensión oral, o...

Dejemos las posibilidades para otro momento y centrémonos en lo concreto. Este es el script que paso a comentarte con detalle a continuación.

import pygame

#Inicializar pygame y pygame.audio
pygame.init()
pygame.mixer.init()

#Componentes MAV
nombres = ("coche","platano","oso","reloj","tijeras","tenedor","estrella","escalera","escoba","cepillo")

#Constantes ventana
ANCHO = 1024 #Tamaño
ALTO = 768
BLANCO = (255,255,255) #Color

#Creación de ventana
ventana = pygame.display.set_mode((ANCHO,ALTO))
ventana.fill(BLANCO)
pygame.display.set_caption('NOMBRES. Conocimiento léxico')

#Bucle for para recorrer la lista de componentes (img y aud)

for i in range(0,10):

    #Imagen
    img_v = "assets/img/" + nombres[i] + ".jpg"
    img = pygame.image.load(img_v)
    img_bis = pygame.transform.scale(img.convert(), (ANCHO,ALTO))
    ventana.blit(img_bis,(0,0))

    # Audio
    aud = "assets/audio/" + nombres[i] + ".mp3"
    pygame.mixer.music.load(aud)
    pygame.mixer.music.play(0)
    pygame.mixer.music.set_volume(0.5)

    #Actualizar ventana
    pygame.display.update()
    #Tiempo visualización
    pygame.time.delay(2000)

pygame.quit()

Como puedes ver, este script se divide en tres partes:
  • La primera va desde el inicio (import pygame) hasta el for
  • La segunda desarrolla el ciclo for (for i in range(0,10):)
  • Y la tercera se ocupa del cierre del programa (pygame.quit())
Respecto a entradas anteriores, la diferencia de la actual, en lo que al inicio se refiere, es la presencia de una tupla que contiene los nombres de los archivos auxiliares (img y aud) que previamente he almacenado en el directorio assets con nombres acordes a los que ahora reproduzco en dicha tupla. Esto me ahorra tener que crear dos tuplas, una para img y otra para aud. Pequeño truquito para trabajar menos.

Con todo, lo que realmente hace que funcione nuestro programa es el uso del bucle for que, como se puede apreciar, se subdivide a su vez en tres partes:
  • En la primera (II.a) trabajamos con las imágenes
  • En la segunda (II.b) con los sonidos
  • Y en la tercera (II.c) actualizamos ventana (pygame.display.update()) y establecemos tiempo de visionado (pygame.time.delay(2000)). Por cierto, podríamos incluir una tercera tupla con los tiempos de duración de los audios y usarlos como parámetros de time.delay(). Sería una interesante propuesta de mejora.
El código de trabajo con img y aud ya es conocido de entradas anteriores: el de img de cuando planteamos usar una imagen como [fondo de pantalla] y el de sonido de [esta entrada], pero en ambas constituye 'novedad' el uso de sendas variables construidas mediante concatenación (vg.img_v = "assets/img/" + nombres[i] + ".jpg") aprovechando la variable contador del bucle. Estas variables son las que se emplean en la instrucción correspondiente (vg. pygame.mixer.music.load(aud)) para cargar respectivamente img y aud.

Y con esto está explicado todo: gracias al bucle, vamos actualizando img y aud para que, tras un lapso de tiempo, se visualicen en la ventana (y se escuchen) los objetos que cargamos en ella de modo secuencial. 

Documento. [Aquí te dejo enlace] para que descargues script y archivos de imágenes y audios.  Se trata de una archivo comprimido que deberás descomprimir, respetando eso sí la estructura de carpetas.

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.