Incluyo aquí este tutorial porque es un tema que me resulta curioso y porque estoy desarrollando este juego en python con pygame.
Se trata de un juego muy sencillo, en el que hay que hacer clic sobre una de las letras que se presentan y conectarla con otras letras para formar diferentes palabras. Una vez que se forme una palabra, si es correcta, se añadirá al crucigrama que se encuentra a la izquierda de las letras disponibles, y si se completa el crucigrama se avanzará al siguiente nivel.
Para implementar esto parto de los siguientes requisitos:
1.- La letra que inicia todas las conexiones entre letras se selecciona mediante clic del botón izquerdo del ratón.2.- A partir de la letra anterior (la primera de las conexiones) y mientras se mantenga pulsado el botón izquierdo del ratón, se van conectado con una línea las letras sobre las que pase el ratón y, si en un momento dado se vuelve a la anteúltima conectada, se deshará (borrará) la última conexión, convirténdose la anteúltima en el inicio de la conexión en curso.
3.- Si se completase una palabra se comprobaría si es correcta y, si es así, se incluiría en el crucigrama que figura a la izquierda de las letras (ésto no se realiza en este pequeño tutorial, ya que éste pretende centrarse exclusivamente en el establecimiento de las conexiones), mientras que si se suelta el botón izquierdo del ratón sin completar una palabra se borrarán todas las conexiones realizadas hasta el momento.
4.- Mediante un icono situado en el centro del círculo donde están las letras, se pueden barajar o mezclar aleatoriamente estas últimas. Muchas veces, el cambiar la posición de las letras, nos puede facilitar encontrar las palabras correctas.
En 'Words of Wonders' (WoW), a medida que se avanza en el juego, se van descubriendo nuevas culturas y lugares icónicos (las maravillas), y en mi versión se irán descubriendo las maravillas del universo.
Dicho lo cual, el script realizado para ésto, es el siguiente:
1.- Importar las librerías necesarias:
import pygame
import os
from random import shuffle
El método shuffle se importa de la librería random para mezclar o barajar las letras. Este método toma una lista y baraja aleatoriamente sus elementos. Es importante tener en cuenta que este método modifica la lista original con los elementos reordenados.
2.- Inicializar pygame, crear ventana, cargar archivos de fuentes y sonidos, crear instancias de los objetos y los grupos de sprites, e inicializar variables:
def conector_letras():
# Inicializar módulos internos de pygame.
pygame.init()
# Establecer tamaño de la ventana.
ancho_pantalla, alto_pantalla = 1248, 702
# Crear una superficie de visualización: la ventana, y centrarla.
os.environ['SDL_VIDEO_CENTERED']='1'
ventana = pygame.display.set_mode((ancho_pantalla, alto_pantalla))
# Título de la ventana.
pygame.display.set_caption('Conector de letras')
# Cargar la imagen del fondo del nivel 1 y cambiar el formato de píxel para crear una copia que se dibujará más rápidamente en la
# pantalla.
fondo_1 = pygame.image.load('recursos/imagenes/fondo_1.png')
fondo_1 = fondo_1.convert()
# Fuentes.
arial_40_negrita = pygame.font.SysFont('arial', 40, bold=True)
arial_65_negrita = pygame.font.SysFont('arial', 65, bold=True)
# Cargar archivos de sonidos.
sonido_musica_fondo = pygame.mixer.Sound('recursos/sonidos/musica_fondo.wav')
sonido_seleccionar = pygame.mixer.Sound('recursos/sonidos/seleccionar.wav')
sonido_deshacer = pygame.mixer.Sound('recursos/sonidos/deshacer.wav')
sonido_barajar = pygame.mixer.Sound('recursos/sonidos/barajar.wav')
# Nivel del juego.
nivel = 1
# Crear canales para sonidos simultáneos.
canal1 = pygame.mixer.Channel(0)
canal2 = pygame.mixer.Channel(1)
# Grupo individual para el botón que permite barajar las letras.
grupo_boton_mezclar = pygame.sprite.GroupSingle()
boton_mezclar = Boton_Mezclar(ancho_pantalla // 2 + 440, alto_pantalla // 2 + 20)
grupo_boton_mezclar.add(boton_mezclar)
# Círculos de las letras de las palabras a adivinar (nivel del juego, número de círculo, sprite del círculo, letra, coordenadas 'x' e 'y'
# absolutas del círculo, y coordenadas 'x' e 'y' de la letra relativas al centro del círculo.
circulos = [(1, 1, None, 'A', ancho_pantalla // 2 + 435, alto_pantalla // 2 - 60, None, None),
(1, 2, None, 'I', ancho_pantalla // 2 + 508, alto_pantalla // 2 + 65, None, None),
(1, 3, None, 'D', ancho_pantalla // 2 + 372, alto_pantalla // 2 + 65, None, None)]
# Grupo de sprites. Agrupamos los círculos donde se inscriben las letras que forman parte de la palabra usando la clase sprite.Group de
# Pygame para hacer que dicha clase se encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo manualmente.
grupo_circulos = pygame.sprite.Group()
for circulo_letra in range(len(circulos)):
if circulos[circulo_letra][0] > nivel - 1 and circulos[circulo_letra][0] < nivel + 1:
circulo = Circulo(circulos[circulo_letra][4], circulos[circulo_letra][5])
lista_tupla_circulos = list(circulos[circulo_letra])
lista_tupla_circulos[2] = circulo
if lista_tupla_circulos[3] == 'I':
lista_tupla_circulos[6] = circulo.rect.center[0] - 8
else:
lista_tupla_circulos[6] = circulo.rect.center[0] - 18
lista_tupla_circulos[7] = circulo.rect.center[1] - 40
circulos[circulo_letra] = tuple(lista_tupla_circulos)
grupo_circulos.add(circulo)
# Grupo de sprites. Agrupamos los círculos que han sido seleccionados usando la clase sprite.Group de Pygame para hacer que dicha clase
# se encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo manualmente.
grupo_circulos_seleccionados = pygame.sprite.Group()
# Lista para las líneas que van conectando círculos en una misma conexión.
lista_lineas = []
# Palabra que se va a intentar como palabra a adivinar.
palabra = ''
# Variable booleana que indica si se ha producido una colision con un círculo que no ha sido previamente seleccionado.
colision_no_seleccionado = False
# Variable booleana que indica si hay que barajar las letras.
barajar = False
# Hacer que suene la música de fondo del juego.
canal1.play(sonido_musica_fondo, -1)
# Reloj para ejecutar el videojuego.
reloj = pygame.time.Clock()
# El juego se ejecutará a 60 frames por segundo.
fps = 60
3.- Bucle principal del juego:
while True:
# Ejecutar el siguiente frame.
reloj.tick(fps)
# Escuchar cada uno de los eventos de la lista de eventos de Pygame.
for evento in pygame.event.get():
# Finalizar el juego cuando se produzca el evento de terminación del programa (cierre de la ventana).
if evento.type == pygame.QUIT:
pygame.quit()
return
# Comprobar si se ha realizado click del botón izquierdo del ratón.
elif evento.type == pygame.MOUSEBUTTONDOWN:
if evento.button == 1:
if len(grupo_circulos_seleccionados) == 0:
# Obtener posición del puntero del ratón.
posicion_raton = pygame.mouse.get_pos()
# Comprobar si se ha realizado click del botón izquierdo del ratón sobre alguno de los circulos.
for circulo in range(len(circulos)):
desp_x =posicion_raton[0] - circulos[circulo][2].rect.x
desp_y =posicion_raton[1] - circulos[circulo][2].rect.y
# Verificar si el puntero está dentro de la máscara del círculo.
if circulos[circulo][2].rect.collidepoint(posicion_raton):
if circulos[circulo][2] not in grupo_circulos_seleccionados:
if circulos[circulo][2].mask.get_at((desp_x, desp_y)):
canal2.play(sonido_seleccionar)
# Incluir el círculo seleccionado en el grupo de círculos seleccionados, mostrar la imagen
# correspondiente a la selección de círculos y poner la letra como primera de la palabra que se va
# a intentar que coincida con una de las que hay que adivinar.
grupo_circulos_seleccionados.add(circulos[circulo][2])
circulos[circulo][2].seleccionar()
palabra = palabra + circulos [circulo][3]
# Indicar que el círculo sobre el que se ha hecho click es el inicio de la conexión en curso, poner
# el puntero del ratón en su centro y a este último como inicio de la línea de conexión.
circulo_inicio = circulos[circulo][2]
pygame.mouse.set_pos(circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
inicio_linea = (circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
break
if len(grupo_circulos_seleccionados) == 0:
# Comprobar si se debe barajar.
if boton_mezclar.rect.collidepoint(posicion_raton) and not barajar:
barajar = True
# Comprobar si se ha soltado (liberado) el botón izquierdo del ratón.
elif evento.type == pygame.MOUSEBUTTONUP:
if evento.button == 1:
if len(grupo_circulos_seleccionados) > 0:
# Eliminar los círculos seleccionados del grupo de círculos seleccionados y todas las líneas de conexión.
grupo_circulos_seleccionados.empty()
lista_lineas =[]
# Comprobar si se ha completado una palabra.
if len(palabra) == len(grupo_circulos):
print('*** Comprobar la palabra formada.')
# Borrar el contenido de la palabra a intentar que coincida con una de las que hay que adivinar.
palabra = ''
else:
while barajar:
# Hacer una copia de las lista de circulos. Esta lista es la que será barajada.
circulos_barajados = circulos.copy()
# Barajar la lista de circulos_barajados (copia de la lista círculos).
boton_mezclar.barajar(circulos_barajados)
for circulo_barajado in range(len(boton_mezclar.circulos)):
if boton_mezclar.circulos[circulo_barajado][3] != circulos[circulo_barajado][3]:
canal2.play(sonido_barajar)
barajar = False
break
if not barajar:
# Modificar las letras en los círculos conforme a lo obtenido al barajar.
for circulo_barajado in range(len(boton_mezclar.circulos)):
lista_tupla_circulos = list(circulos[circulo_barajado])
lista_tupla_circulos[3] = boton_mezclar.circulos[circulo_barajado][3]
if lista_tupla_circulos[3] == 'I':
lista_tupla_circulos[6] = lista_tupla_circulos[2].rect.center[0] - 8
else:
lista_tupla_circulos[6] = lista_tupla_circulos[2].rect.center[0] - 18
lista_tupla_circulos[7] = lista_tupla_circulos[2].rect.center[1] - 40
circulos[circulo_barajado] = tuple(lista_tupla_circulos)
# Seguimiento del movimiento del ratón.
elif evento.type == pygame.MOUSEMOTION:
if len(grupo_circulos_seleccionados) > 0:
# Obtener posición del puntero del ratón.
posicion_raton = pygame.mouse.get_pos()
# Comprobar si el puntero del ratón colisiona con algún círculo que no esté previamente seleccionado.
for circulo in range(len(circulos)):
desp_x = posicion_raton[0] - circulos[circulo][2].rect.x
desp_y = posicion_raton[1] - circulos[circulo][2].rect.y
# Verificar si el puntero está dentro de la máscara del círculo.
if circulos[circulo][2].rect.collidepoint(posicion_raton):
if circulos[circulo][2] not in grupo_circulos_seleccionados:
if circulos[circulo][2].mask.get_at((desp_x, desp_y)):
canal2.play(sonido_seleccionar)
# colision con un círculo que no ha sido previamente seleccionado.
colision_no_seleccionado = True
# Incluir el círculo seleccionado en el grupo de círculos seleccionados, mostrar la imagen
# correspondiente a la selección de círculos y poner la letra como siguiente de la palabra
# que se va a intentar que coincida con una de las que hay que adivinar.
grupo_circulos_seleccionados.add(circulos[circulo][2])
circulos[circulo][2].seleccionar()
palabra = palabra + circulos [circulo][3]
# Incluir la línea de conexión en la lista de líneas de conexión.
lista_lineas.append((circulo_inicio.rect.center[0], circulo_inicio.rect.center[1],
circulos[circulo][2].rect.center[0], circulos[circulo][2].rect.center[1]))
# Indicar que el círculo seleccionado es el inicio de la conexión en curso, poner el puntero del
# ratón en su centro y a este último como inicio de la línea de conexión.
circulo_inicio = circulos[circulo][2]
pygame.mouse.set_pos(circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
inicio_linea = (circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
break
if not colision_no_seleccionado:
lista_circulos_seleccionados = pygame.sprite.Group.sprites(grupo_circulos_seleccionados)
if len(lista_circulos_seleccionados) > 1:
# Calcular la posición relativa del puntero del ratón respecto a la esquina superior izquierda del
# anteúltimo círculo seleccionado.
desp_x = posicion_raton[0] - lista_circulos_seleccionados[-2].rect.x
desp_y = posicion_raton[1] - lista_circulos_seleccionados[-2].rect.y
# Verificar si el puntero está dentro de la máscara del círculo.
if lista_circulos_seleccionados[-2].rect.collidepoint(posicion_raton):
if lista_circulos_seleccionados[-2].mask. get_at((desp_x, desp_y)):
canal2.play(sonido_deshacer)
# Mostrar la imagen de círculo no seleccionado para el último círculo seleccionado, eliminar éste
# del grupo de círculos seleccionados, eliminar la última línea de conexión y borrar la última letra
# de la palabra a intentar que coincida con una de las que hay que adivinar.
lista_circulos_seleccionados[-1].deshacer()
grupo_circulos_seleccionados.remove(lista_circulos_seleccionados[-1])
lista_lineas.remove(lista_lineas[-1])
palabra = palabra[:-1]
# Indicar que el anteúltimo círculo seleccionado es el inicio de la conexión en curso, poner el
# puntero del ratón en su centro y a este último como inicio de la línea de conexión.
circulo_inicio=lista_circulos_seleccionados[-2]
pygame.mouse.set_pos(circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
inicio_linea = (circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
else:
colision_no_seleccionado = False
# Actualizar sprites.
grupo_circulos.update()
# Imagen de fondo del nivel 1.
ventana.blit(fondo_1, (0, 0))
# Dibujar el círculo que contendrá las letras.
pygame.draw.circle(ventana,(250, 240, 230), (ancho_pantalla // 2 + 440, alto_pantalla // 2 + 20), 125)
# Dibujar las líneas que conectan círculos en una misma conexión de círculos.
for linea in range(len(lista_lineas)):
if lista_lineas[linea][1] == lista_lineas[linea][3]:
grosor = 10
else:
grosor = 13
pygame.draw.line(ventana, (164, 19, 47), (lista_lineas[linea][0], lista_lineas[linea][1]),
(lista_lineas[linea][2], lista_lineas[linea][3]),
grosor)
# Dibujar botón mezclar.
grupo_boton_mezclar.draw(ventana)
# Dibujar la línea de la conexión en curso.
if len(grupo_circulos_seleccionados) > 0:
pygame.draw.line(ventana, (164, 19, 47), inicio_linea, evento.pos, 12)
# Dibujar los círculos.
grupo_circulos.draw(ventana)
# Poner las letras de la palabra en los círculos.
for num_circulo in range(len(circulos)):
if circulos[num_circulo][0] > nivel - 1 and circulos[num_circulo][0] < nivel + 1:
if circulos[num_circulo][2] not in grupo_circulos_seleccionados:
circulos[num_circulo][2].deshacer()
texto_letra = arial_65_negrita.render(circulos[num_circulo][3], 0, (60, 66, 107))
else:
texto_letra = arial_65_negrita.render(circulos[num_circulo][3], 0, (255, 255, 255))
texto_palabra = arial_40_negrita.render(palabra, 0, (255, 255, 255))
ventana.blit(texto_palabra, (ancho_pantalla // 2 + 400, alto_pantalla // 2 - 150))
ventana.blit(texto_letra, (circulos[num_circulo][6], circulos[num_circulo][7]))
pygame.display.flip()
pygame.quit()
Como se observa, cuando se presiona el botón izquierdo del ratón (evento 'MOUSEBUTTONDOWN'), se comprueba si se ha realizado clic sobre la máscara (ver tutoriales sobre colisiones precisas: 'Python + Pygame (XXXI): Tutorial - Colisiones precisas (I)' y 'Python + Pygame (XXXII): Tutorial - Colisiones precisas (II)') de alguno de los círculos en los que se inscriben las letras (estos círculos, todavía no seleccionados, no se ven porque su color es el mismo que el del círculo grande que contiene a todos ellos). Si es así, se selecciona el círculo sobre el que se ha hecho clic, es decir, se incluye éste en el grupo de círculos seleccionados, se muestra la imágen correspondiente al círculo seleccionado y se pone la letra inscrita en el mismo como primera de la palabra que se va a intentar que coincida con una de las que hay que adivinar.Además, se pone el círculo sobre el que se ha hecho clic como el primero de las conexiones en curso, el puntero del ratón en el centro del círculo y a este último como inicio de la línea de conexión.
En el caso de que no se haya realizado clic sobre la máscara de alguno de los círculos, se comprueba si el clic se ha realizado sobre el icono de barajar las letras, en cuyo caso se indica que se debe barajar.
Cuando se libera o suelta el botón izquierdo del ratón (evento 'MOUSEBUTTONUP'), si se estaba seleccionando círculos, se eliminan todos los círculos seleccionados hasta el momento del grupo correspondiente a los mismos y todas las líneas de conexión entre ellos, y en el caso de haberse completado una palabra se comprueba si es una de las correctas (tal y como se ha indicado, esto no es objeto de este tutorial, mostrándose en el código una sentencia 'print' donde iría el tratamiento para ésto). Además, se borra la palabra que se estaba o ha formando; mientras que si no se estaba seleccionando círculos y el clic se ha hecho sobre el icono de barajar, se cambiará aleatoriamente la posición de las letras, para lo que se utiliza el método 'shuffle' conjuntamente con el método copy (se obtiene una copia de la lista de círculos, que es la que relamente se baraja, y se actualiza la lista original con los datos que nos interesan).
En lo que respecta al seguimiento del movimiento del ratón (evento 'MOUSEMOTION'), si se está seleccionando círculos en los que se inscriben las letras, si el puntero del ratón colisiona con algún círculo que no esté previamente seleccionado, se incluye dicho círculo en el grupo de círculos seleccionados, se muestra la imagen correspondiente a la selección de círculos y se pone la letra inscrita en el círculo como siguiente de la palabra que se va a intentar que coincida con una de las que hay que adivinar.Además, se incluye la línea de conexión en la lista de líneas de conexión, se pone al círculo seleccionado como el de inicio de la conexión en curso, al puntero del ratón en el centro del círculo seleccionado y a este último como inicio de la conexión en curso (inicio de la siguiente línea de conexión).
Mientras que si no hay colisión con algún círculo no previamente seleccionado, se comprueba si la colisión se produce con el anteúltimo círculo seleccionado y, si es el caso se procede a deshacer o eliminar la última conexión: mostrar la imagen de círculo no seleccionado para el último círculo seleccionado, eliminar éste del grupo de círculos seleccionados, eliminar la última línea de conexión y borrar la última letra de la palabra a intentar que coincida con una de las que hay que adivinar. Además, se pone al anteúltimo círculo seleccionado como el de inicio de la conexión en curso, al puntero del ratón en su centro y a este último como inicio de la siguiente línea de conexión.
4.- Clases:
class Boton_Mezclar(pygame.sprite.Sprite):
# El botón que permite barajar las letras estará definido por la clase Boton_Mezclar, que hereda de la clase sprite.Sprite de Pygame.
# Clase base para objetos visibles del juego.
def __init__(self, x, y):
super().__init__()
self.x, self.y = x, y
self.image = pygame.image.load('recursos/imagenes/sprites/boton_mezclar.png').convert_alpha()
self.rect = self.image.get_rect(center=(self.x, self.y))
def barajar(self, circulos):
# Método que permite mezclar o barajar las letras.
self.circulos = circulos
shuffle(self.circulos)
class Circulo(pygame.sprite.Sprite):
# Los círculos en los que están inscritas las letras que forman parte de la palabra estarán definidos por la clase Circulo, que hereda
# de la clase sprite.Sprite de Pygame. Clase base para objetos visibles del juego.
def __init__(self, x, y):
super().__init__()
self.x, self.y = x, y
self.image = pygame.image.load('recursos/imagenes/sprites/circulo_letra_no_seleccionada.png').convert_alpha()
self.rect = self.image.get_rect(center=(self.x, self.y))
self.mask = pygame.mask.from_surface(self.image)
def seleccionar(self):
# Método que muestra la imagen del círculo seleccionado.
self.image = pygame.image.load('recursos/imagenes/sprites/circulo_letra_seleccionada.png').convert_alpha()
def deshacer(self):
# Método que muestra la imagen del círculo no seleccionado.
self.image = pygame.image.load('recursos/imagenes/sprites/circulo_letra_no_seleccionada.png').convert_alpha()
def update(self):
# El método update() se ejecutará en cada frame, y permite actualizar la posición de los círculos.
self.rect = self.image.get_rect(center=(self.x, self.y))
Al final del contructor de la clase 'Circulo' se puede observar la creación del atributo mask de la imagen del sprite, correspondiente al círculo que se instancia, mediante el método pygame.mask.from_surface(surface)
5.- Poniendo todo junto:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# CONECTOR DE LETRAS:
#
# Tipo juego Words of Wonders (WoW).
#
# Autor: Mikel García Larragan.
# https://mikelgarcialarragan.blogspot.com/
import pygame
import os
from random import shuffle
class Boton_Mezclar(pygame.sprite.Sprite):
# El botón que permite barajar las letras estará definido por la clase Boton_Mezclar, que hereda de la clase sprite.Sprite de Pygame.
# Clase base para objetos visibles del juego.
def __init__(self, x, y):
super().__init__()
self.x, self.y = x, y
self.image = pygame.image.load('recursos/imagenes/sprites/boton_mezclar.png').convert_alpha()
self.rect = self.image.get_rect(center=(self.x, self.y))
def barajar(self, circulos):
# Método que permite mezclar o barajar las letras.
self.circulos = circulos
shuffle(self.circulos)
class Circulo(pygame.sprite.Sprite):
# Los círculos en los que están inscritas las letras que forman parte de la palabra estarán definidos por la clase Circulo, que hereda
# de la clase sprite.Sprite de Pygame. Clase base para objetos visibles del juego.
def __init__(self, x, y):
super().__init__()
self.x, self.y = x, y
self.image = pygame.image.load('recursos/imagenes/sprites/circulo_letra_no_seleccionada.png').convert_alpha()
self.rect = self.image.get_rect(center=(self.x, self.y))
self.mask = pygame.mask.from_surface(self.image)
def seleccionar(self):
# Método que muestra la imagen del círculo seleccionado.
self.image = pygame.image.load('recursos/imagenes/sprites/circulo_letra_seleccionada.png').convert_alpha()
def deshacer(self):
# Método que muestra la imagen del círculo no seleccionado.
self.image = pygame.image.load('recursos/imagenes/sprites/circulo_letra_no_seleccionada.png').convert_alpha()
def update(self):
# El método update() se ejecutará en cada frame, y permite actualizar la posición de los círculos.
self.rect = self.image.get_rect(center=(self.x, self.y))
def conector_letras():
# Inicializar módulos internos de pygame.
pygame.init()
# Establecer tamaño de la ventana.
ancho_pantalla, alto_pantalla = 1248, 702
# Crear una superficie de visualización: la ventana, y centrarla.
os.environ['SDL_VIDEO_CENTERED']='1'
ventana = pygame.display.set_mode((ancho_pantalla, alto_pantalla))
# Título de la ventana.
pygame.display.set_caption('Conector de letras')
# Cargar la imagen del fondo del nivel 1 y cambiar el formato de píxel para crear una copia que se dibujará más rápidamente en la
# pantalla.
fondo_1 = pygame.image.load('recursos/imagenes/fondo_1.png')
fondo_1 = fondo_1.convert()
# Fuentes.
arial_40_negrita = pygame.font.SysFont('arial', 40, bold=True)
arial_65_negrita = pygame.font.SysFont('arial', 65, bold=True)
# Cargar archivos de sonidos.
sonido_musica_fondo = pygame.mixer.Sound('recursos/sonidos/musica_fondo.wav')
sonido_seleccionar = pygame.mixer.Sound('recursos/sonidos/seleccionar.wav')
sonido_deshacer = pygame.mixer.Sound('recursos/sonidos/deshacer.wav')
sonido_barajar = pygame.mixer.Sound('recursos/sonidos/barajar.wav')
# Nivel del juego.
nivel = 1
# Crear canales para sonidos simultáneos.
canal1 = pygame.mixer.Channel(0)
canal2 = pygame.mixer.Channel(1)
# Grupo individual para el botón que permite barajar las letras.
grupo_boton_mezclar = pygame.sprite.GroupSingle()
boton_mezclar = Boton_Mezclar(ancho_pantalla // 2 + 440, alto_pantalla // 2 + 20)
grupo_boton_mezclar.add(boton_mezclar)
# Círculos de las letras de las palabras a adivinar (nivel del juego, número de círculo, sprite del círculo, letra, coordenadas 'x' e 'y'
# absolutas del círculo, y coordenadas 'x' e 'y' de la letra relativas al centro del círculo.
circulos = [(1, 1, None, 'A', ancho_pantalla // 2 + 435, alto_pantalla // 2 - 60, None, None),
(1, 2, None, 'I', ancho_pantalla // 2 + 508, alto_pantalla // 2 + 65, None, None),
(1, 3, None, 'D', ancho_pantalla // 2 + 372, alto_pantalla // 2 + 65, None, None)]
# Grupo de sprites. Agrupamos los círculos donde se inscriben las letras que forman parte de la palabra usando la clase sprite.Group de
# Pygame para hacer que dicha clase se encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo manualmente.
grupo_circulos = pygame.sprite.Group()
for circulo_letra in range(len(circulos)):
if circulos[circulo_letra][0] > nivel - 1 and circulos[circulo_letra][0] < nivel + 1:
circulo = Circulo(circulos[circulo_letra][4], circulos[circulo_letra][5])
lista_tupla_circulos = list(circulos[circulo_letra])
lista_tupla_circulos[2] = circulo
if lista_tupla_circulos[3] == 'I':
lista_tupla_circulos[6] = circulo.rect.center[0] - 8
else:
lista_tupla_circulos[6] = circulo.rect.center[0] - 18
lista_tupla_circulos[7] = circulo.rect.center[1] - 40
circulos[circulo_letra] = tuple(lista_tupla_circulos)
grupo_circulos.add(circulo)
# Grupo de sprites. Agrupamos los círculos que han sido seleccionados usando la clase sprite.Group de Pygame para hacer que dicha clase
# se encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo manualmente.
grupo_circulos_seleccionados = pygame.sprite.Group()
# Lista para las líneas que van conectando círculos en una misma conexión.
lista_lineas = []
# Palabra que se va a intentar como palabra a adivinar.
palabra = ''
# Variable booleana que indica si se ha producido una colision con un círculo que no ha sido previamente seleccionado.
colision_no_seleccionado = False
# Variable booleana que indica si hay que barajar las letras.
barajar = False
# Hacer que suene la música de fondo del juego.
canal1.play(sonido_musica_fondo, -1)
# Reloj para ejecutar el videojuego.
reloj = pygame.time.Clock()
# El juego se ejecutará a 60 frames por segundo.
fps = 60
while True:
# Ejecutar el siguiente frame.
reloj.tick(fps)
# Escuchar cada uno de los eventos de la lista de eventos de Pygame.
for evento in pygame.event.get():
# Finalizar el juego cuando se produzca el evento de terminación del programa (cierre de la ventana).
if evento.type == pygame.QUIT:
pygame.quit()
return
# Comprobar si se ha realizado click del botón izquierdo del ratón.
elif evento.type == pygame.MOUSEBUTTONDOWN:
if evento.button == 1:
if len(grupo_circulos_seleccionados) == 0:
# Obtener posición del puntero del ratón.
posicion_raton = pygame.mouse.get_pos()
# Comprobar si se ha realizado click del botón izquierdo del ratón sobre alguno de los circulos.
for circulo in range(len(circulos)):
desp_x =posicion_raton[0] - circulos[circulo][2].rect.x
desp_y =posicion_raton[1] - circulos[circulo][2].rect.y
# Verificar si el puntero está dentro de la máscara del círculo.
if circulos[circulo][2].rect.collidepoint(posicion_raton):
if circulos[circulo][2] not in grupo_circulos_seleccionados:
if circulos[circulo][2].mask.get_at((desp_x, desp_y)):
canal2.play(sonido_seleccionar)
# Incluir el círculo seleccionado en el grupo de círculos seleccionados, mostrar la imagen
# correspondiente a la selección de círculos y poner la letra como primera de la palabra que se va
# a intentar que coincida con una de las que hay que adivinar.
grupo_circulos_seleccionados.add(circulos[circulo][2])
circulos[circulo][2].seleccionar()
palabra = palabra + circulos [circulo][3]
# Indicar que el círculo sobre el que se ha hecho click es el inicio de la conexión en curso, poner
# el puntero del ratón en su centro y a este último como inicio de la línea de conexión.
circulo_inicio = circulos[circulo][2]
pygame.mouse.set_pos(circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
inicio_linea = (circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
break
if len(grupo_circulos_seleccionados) == 0:
# Comprobar si se debe barajar.
if boton_mezclar.rect.collidepoint(posicion_raton) and not barajar:
barajar = True
# Comprobar si se ha soltado (liberado) el botón izquierdo del ratón.
elif evento.type == pygame.MOUSEBUTTONUP:
if evento.button == 1:
if len(grupo_circulos_seleccionados) > 0:
# Eliminar los círculos seleccionados del grupo de círculos seleccionados y todas las líneas de conexión.
grupo_circulos_seleccionados.empty()
lista_lineas =[]
# Comprobar si se ha completado una palabra.
if len(palabra) == len(grupo_circulos):
print('*** Comprobar la palabra formada.')
# Borrar el contenido de la palabra a intentar que coincida con una de las que hay que adivinar.
palabra = ''
else:
while barajar:
# Hacer una copia de las lista de circulos. Esta lista es la que será barajada.
circulos_barajados = circulos.copy()
# Barajar la lista de circulos_barajados (copia de la lista círculos).
boton_mezclar.barajar(circulos_barajados)
for circulo_barajado in range(len(boton_mezclar.circulos)):
if boton_mezclar.circulos[circulo_barajado][3] != circulos[circulo_barajado][3]:
canal2.play(sonido_barajar)
barajar = False
break
if not barajar:
# Modificar las letras en los círculos conforme a lo obtenido al barajar.
for circulo_barajado in range(len(boton_mezclar.circulos)):
lista_tupla_circulos = list(circulos[circulo_barajado])
lista_tupla_circulos[3] = boton_mezclar.circulos[circulo_barajado][3]
if lista_tupla_circulos[3] == 'I':
lista_tupla_circulos[6] = lista_tupla_circulos[2].rect.center[0] - 8
else:
lista_tupla_circulos[6] = lista_tupla_circulos[2].rect.center[0] - 18
lista_tupla_circulos[7] = lista_tupla_circulos[2].rect.center[1] - 40
circulos[circulo_barajado] = tuple(lista_tupla_circulos)
# Seguimiento del movimiento del ratón.
elif evento.type == pygame.MOUSEMOTION:
if len(grupo_circulos_seleccionados) > 0:
# Obtener posición del puntero del ratón.
posicion_raton = pygame.mouse.get_pos()
# Comprobar si el puntero del ratón colisiona con algún círculo que no esté previamente seleccionado.
for circulo in range(len(circulos)):
desp_x = posicion_raton[0] - circulos[circulo][2].rect.x
desp_y = posicion_raton[1] - circulos[circulo][2].rect.y
# Verificar si el puntero está dentro de la máscara del círculo.
if circulos[circulo][2].rect.collidepoint(posicion_raton):
if circulos[circulo][2] not in grupo_circulos_seleccionados:
if circulos[circulo][2].mask.get_at((desp_x, desp_y)):
canal2.play(sonido_seleccionar)
# colision con un círculo que no ha sido previamente seleccionado.
colision_no_seleccionado = True
# Incluir el círculo seleccionado en el grupo de círculos seleccionados, mostrar la imagen
# correspondiente a la selección de círculos y poner la letra como siguiente de la palabra
# que se va a intentar que coincida con una de las que hay que adivinar.
grupo_circulos_seleccionados.add(circulos[circulo][2])
circulos[circulo][2].seleccionar()
palabra = palabra + circulos [circulo][3]
# Incluir la línea de conexión en la lista de líneas de conexión.
lista_lineas.append((circulo_inicio.rect.center[0], circulo_inicio.rect.center[1],
circulos[circulo][2].rect.center[0], circulos[circulo][2].rect.center[1]))
# Indicar que el círculo seleccionado es el inicio de la conexión en curso, poner el puntero del
# ratón en su centro y a este último como inicio de la línea de conexión.
circulo_inicio = circulos[circulo][2]
pygame.mouse.set_pos(circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
inicio_linea = (circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
break
if not colision_no_seleccionado:
lista_circulos_seleccionados = pygame.sprite.Group.sprites(grupo_circulos_seleccionados)
if len(lista_circulos_seleccionados) > 1:
# Calcular la posición relativa del puntero del ratón respecto a la esquina superior izquierda del
# anteúltimo círculo seleccionado.
desp_x = posicion_raton[0] - lista_circulos_seleccionados[-2].rect.x
desp_y = posicion_raton[1] - lista_circulos_seleccionados[-2].rect.y
# Verificar si el puntero está dentro de la máscara del círculo.
if lista_circulos_seleccionados[-2].rect.collidepoint(posicion_raton):
if lista_circulos_seleccionados[-2].mask. get_at((desp_x, desp_y)):
canal2.play(sonido_deshacer)
# Mostrar la imagen de círculo no seleccionado para el último círculo seleccionado, eliminar éste
# del grupo de círculos seleccionados, eliminar la última línea de conexión y borrar la última letra
# de la palabra a intentar que coincida con una de las que hay que adivinar.
lista_circulos_seleccionados[-1].deshacer()
grupo_circulos_seleccionados.remove(lista_circulos_seleccionados[-1])
lista_lineas.remove(lista_lineas[-1])
palabra = palabra[:-1]
# Indicar que el anteúltimo círculo seleccionado es el inicio de la conexión en curso, poner el
# puntero del ratón en su centro y a este último como inicio de la línea de conexión.
circulo_inicio=lista_circulos_seleccionados[-2]
pygame.mouse.set_pos(circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
inicio_linea = (circulo_inicio.rect.center[0], circulo_inicio.rect.center[1])
else:
colision_no_seleccionado = False
# Actualizar sprites.
grupo_circulos.update()
# Imagen de fondo del nivel 1.
ventana.blit(fondo_1, (0, 0))
# Dibujar el círculo que contendrá las letras.
pygame.draw.circle(ventana,(250, 240, 230), (ancho_pantalla // 2 + 440, alto_pantalla // 2 + 20), 125)
# Dibujar las líneas que conectan círculos en una misma conexión de círculos.
for linea in range(len(lista_lineas)):
if lista_lineas[linea][1] == lista_lineas[linea][3]:
grosor = 10
else:
grosor = 13
pygame.draw.line(ventana, (164, 19, 47), (lista_lineas[linea][0], lista_lineas[linea][1]),
(lista_lineas[linea][2], lista_lineas[linea][3]),
grosor)
# Dibujar botón mezclar.
grupo_boton_mezclar.draw(ventana)
# Dibujar la línea de la conexión en curso.
if len(grupo_circulos_seleccionados) > 0:
pygame.draw.line(ventana, (164, 19, 47), inicio_linea, evento.pos, 12)
# Dibujar los círculos.
grupo_circulos.draw(ventana)
# Poner las letras de la palabra en los círculos.
for num_circulo in range(len(circulos)):
if circulos[num_circulo][0] > nivel - 1 and circulos[num_circulo][0] < nivel + 1:
if circulos[num_circulo][2] not in grupo_circulos_seleccionados:
circulos[num_circulo][2].deshacer()
texto_letra = arial_65_negrita.render(circulos[num_circulo][3], 0, (60, 66, 107))
else:
texto_letra = arial_65_negrita.render(circulos[num_circulo][3], 0, (255, 255, 255))
texto_palabra = arial_40_negrita.render(palabra, 0, (255, 255, 255))
ventana.blit(texto_palabra, (ancho_pantalla // 2 + 400, alto_pantalla // 2 - 150))
ventana.blit(texto_letra, (circulos[num_circulo][6], circulos[num_circulo][7]))
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
conector_letras()
Si lo ejecutamos:
Quizás también te interese:
Comentarios
Publicar un comentario