Juego en Pygame - Piedra Spock Papel Lagarto y Tijera
Piedra-Spock-Papel-Lagarto-Tijera |
Este juego en PyGame es una variante del clásico juego "piedra, papel o tijera" que ya se vio hace tiempo en el blog: Piedra, papel o tijera en python, con la diferencia que se agregan dos manos: Spock y Lagarto.
Puedes ver la explicación del juego en este enlace: http://es.wikihow.com/jugar-piedra,-papel,-tijera,-lagarto,-spock
Aquí te dejo la famosa explicación que dio Sheldon Cooper de The Bing Bang Theory:
Pues en esta entrada recrearemos este juego con todo y su interfaz gráfica, terminaremos con nuestro propio y funcional juego de "piedra-spock-papel-lagarto-tijeras" puffff, un nombre bastante largo para un juego ¿no creen?, así que por motivos prácticos lo llamaremos PSPTL.. (a veces me asombro por mi originalidad xD).
El juego se verá así:
Vista del juego en PyGame |
Función del juego
En la parte inferior se muestran los botones para seleccionar una mano y una vez seleccionada aparecerán en el medio de la pantalla la mano que seleccionamos contra la que seleccionó la computadora mostrando los resultados: ganas, pierdes o empate y actualizando las correspondientes puntuaciones.
Antes de empezar quiero aclarar que es recomendable un nivel medio de Python para entender todos los conceptos que manejare más adelante. Puedes pasarte por el Tutorial Python si recién están comenzando. Pero aún si no entiendes muchas cosas te animo a seguir, tu escribes el código tal y como te lo muestro aunque no lo entiendas del todo, todo esto es parte de aprender a programar, poco a poco tu mente se irá despejando y si continuas aprendiendo, te acordaras de aquel día que viste este tutorial con el que hiciste el juego PSPLT que en su momento no entendías mucho, pero ahora si (créeme, así me ha pasado muchas veces).
Por último yo utilizo Sublime Text 2 como editor de texto y ejecuto el programa de 2 maneras:
1 - Ejecutando el archivo .py por medio del símbolo del sistema (CMD).
2 - En Sublime Text si presiona las teclas "Ctrl + B", el código se ejecutará.
Por último es necesario tener instalado la versión de Python 2.7.9 y PyGame 1.9.1 (para python 2.7)
Quye puedes descargar aquí:
Python 2.7.9 --> https://www.python.org/ftp/python/2.7.9/python-2.7.9.msi
Sin más, empezamos:
Primeramente descarga este archivo y lo descomprimes en una carpeta: https://www.dropbox.com/s/k9fdpu3cm45m4ic/PSPTL.rar?dl=1
Dentro vienen los recursos que necesitaremos para crear nuestro juego (plantilla e imágenes png).
Abrimos la plantilla en el editor de texto de nuestra preferencia, esta la podemos utilizar para cualquier proyecto PyGame que tengan en mente y que quieran realizar, esta se divide en:
MÓDULOS: aquí importamos todos los módulos que vallamos a ocupar en nuestro programa.
CONSTANTES: aquí declaramos las constantes, es decir, valores que no cambian nunca y se escriben en mayúsculas.
FUNCIONES DE AYUDA: aquí creamos las funciones que utilizas constantemente a lo largo de todo tu código y no son exclusivas de alguna clase.
CLASES: aquí van las clases de tu código (duuhh!!).
FUNCIÓN PRINCIPAL: esta es la encargada de que la magia ocurra... =D.
Si ejecutas el código se abrirá una ventana con las dimensiones y etiquetas especificadas en la función main(), así:
Ventana del juego en PyGame |
Un breve análisis de la plantilla
Módulos |
La primera línea #! Enconding: utf-8 es importante si queremos escribir el famoso acento (áéíóú) entre otros caracteres especiales. Importamos los módulos Pygame, random y sys que ucuparemos en nuestro programa.
Constantes |
He creado estas constantes que utilizaremos más adelante.
Funciones de ayuda |
Esta es una función que nos facilitara el dibujado de caracteres en la ventana: más información sobre el módulo pygame.font.Font aquí: http://www.pygame.org/docs/ref/font.html#pygame.font.Font
Clases |
Aquí crearemos las clases necesarias.
main() |
Principal |
Bueno, ya estamos a un paso menos de crear nuestro emocionante juego PSPLT.
Continuando...
CLASES:
Clase Manos |
Método __init__ |
pygame.sprite.Sprite *por el momento no es necesario que entiendan sobre clases padres y subclases, esta es la sintaxis que pide la documentación de PyGame para que funcione, más información aquí: http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite
Linea 36 - self.rect.topleft asigna la posición que va a tener en la pantalla la imagen con los valores x e y.
Esta clase tendrá 4 métodos:
Métodos de la clase Manos |
Bien, hemos construido el molde, pero ahora vamos a utilizarlo, así que crearemos una clase que se va a encargar de eso de la lógica del juego que llamaremos Juego()
Clase Juego() |
La clase Juego() también va a contar con su método inicializador.
Linea 63 a 72 - Primero creamos una lista vacía self.manos donde guardaremos las 5 manos de nuestro juego, creo una variable posicion_inicial a la que le asigno la posición vertical que tendrán nuestras manos en la pantalla.
Enseguida vamos a utilizar nuestra clase Manos para crear las 5 manos del juego; vamos a crear la mano "piedra" de la siguiente manera:
Manos(piedra", 10, posicion_vertical) regresando un poco cuando estábamos creando la clase Manos...¿recuerdan que a esta le pusimos que pidiera los parámetros texto, x e y? pues con esta línea estamos diciendo que se cree un objeto en donde sus características serán texto = "piedra", x = 10 e y = posicion_vertical.
Y con self.manos.append() le estamos diciendo que ese objeto lo agregue a la lista self.manos.
Al crear las 5 manos vamos a terminar con una lista que contiene 5 objetos; self.mano = [Objeto1, Objeto2, Objeto3, Objeto4, Objeto5] y cada uno de estos objetos con sus respectivas características.
Por último self.todos_los_sprites = pygame.sprite.Group(self.manos) es una característica de pygame que nos permite controlar más fácilmente listas de objetos creados con el módulo pygame.sprite.Sprite (revisa la documentación de PyGame para más información) * Como dije anteriormente no necesitas entenderlo por el momento solo escríbelo.
Linea 74 a 79 - las primeras 3 variables son para almacenar que escogió el jugador, la computadora y el resultado, las siguientes 3 preparamos el texto que se va mostrar en la pantalla apoyándonos de la función de ayuda texto().
Linea 81 a 89 - en self.vs_image guardo la imagen de vs que aparecerá al centro, self.mano_seleccionada guardara la mano que hallamos seleccionado al soltar el click sobre una de las manos, self.jugador_imagen y self.comp_imagen guardaremos una copia de las imágenes que seleccionaron el jugador y la computadora por juego y por último self.puntuacion que ya se imaginaran para que es.
Enseguida nuestra clase Juego() contara con 9 métodos:
Los primeros 5:
5 métodos de la clase Juego() |
El método copiar_imagen() nos regresara una copia de la imagen amplificada con pygame.transform.scale que le corresponda al nombre que le demos, por ejemplo imagen_piedra = copiar_imagen("piedra") con esto guardamos una copia de la imagen de la mano piedra en la variable imagen_piedra.
El método obtener_manos() simplemente me regresa la lista self.manos
El método seleccionar() guarda en la variable self.mano_seleccionada la mano u objeto en la que hayamos dado un click.
El método obtener_mano_seleccionada() nos regresara que mano tenemos seleccionada en ese momento.
El método dibujar() que le pasamos el parámetro pantalla que es en donde vamos a dibujar nuestro juego.
Con pantalla.blit() dibujamos y colocamos todos los textos e imágenes que mostrará nuestro juego.
Noten que hay una condición if self.jugador_imagen esta variable la iniciamos como None por lo que la condición if la considera como Falso y no dibujara lo que esta contenga hasta que tengamos una imagen en la variable.
Al final con self.todos_los_sprites.draw(pantalla) dibujamos todas las manos.
Los siguientes 3 métodos vienen siendo el corazón del juego, la lógica que determina si ganas, pierdes o empatas:
3 métodos de la clase Juego() |
El método nombre_a_numero() regresa un número dependiendo de la mano que introduzcamos. Ej. nombre_a_numero("papel") nos regresa 2.
El método numero_a_nombre() hace lo contrario al método anterior, introducimos un número y nos regresa la mano correspondiente.
Y el método principal jugar() se le pasa la mano que escogió el jugador:
Guardamos el nombre de la mano en self.jugador_escoge, guardamos la imagen de la mano que escogió el jugador en self.jugador_imagen y guardamos el número que le corresponde a la mano del jugador en numero_jugador.
Guardamos un número al azar del 0 al 4 en numero_comp, guardamos el nombre que le corresponde a ese número en self.comp_escoge y guardamos la imagen que le corresponde al nombre en self.comp_imagen.
Aquí viene lo interesante que es determinar el resultado. Pudimos haber hecho una larga lista de sentencias if y elif con todos los diferentes casos para obtenerlo pero buscando un poco en Internet encontré este pequeño código que nos evita todo eso:
res = (numero_jugador - nombre_comp) % 5
Y dependiendo del número que se almacene en res podemos determinar el resultado con las últimas 3 sentencias if y elif... Genial!!! y dependiendo de quién gana, asignamos sus respetiva puntuación.
Y por último:
Método actualizar() |
El método actualizar():
*esta parte puede ser confusa así que tratare de explicar lo mejor posible
Con pygame.mouse.get_pressed()[0] detecta cuando tenemos presionado el click izquierdo, con pygame.mouse._get_pos() guardamos en la variable mouse la posición que tiene es ese momento el mouse, con self.seleccionar(None) llamamos al método de la clase en la que nos encontramos (Juego()) para resetear la variable self.mano_seleccionada (en caso de que tengamos otra mano almacenada).
Con for mano in self.obtener_manos() recorremos nuestras 5 manos y en la condición if llamamos al método obtener_rect() de la mano en la que nos encontramos y así mismo llamamos otro método de nuestra librería pygame .collidepoint(mouse), lo que hace es detectar si el mouse se encuentra encima de la imagen de la mano.
En resumen... sería:
Si (if) mantenemos el click izquierdo encima de alguna de las manos, utiliza el método mano.presionar(True) para decirle a esa mano que está siendo presionada y con self.presionar(mano) la guarda en mi variable self.mano_seleccionada.
De lo contrario (else) usa mano.presionar(False).
* Si lo se, yo también tarde en entender todo esto.
Muy bien... ya casi terminamos, solo nos falta hacer funcionar todo esto por medio de nuestra función principal main() como dije anteriormente, aquí es donde la magia ocurre xD, es decir, donde conectamos todos los eventos ayudándonos de los métodos que hemos creado para cada clase con el fin de que todo funcione correctamente.
Nuestra gloriosa función principal:
Función principal del Juego |
Aquí solo hay 2 diferencias con respecto a la plantilla:
1 - hemos cambiado el nombre de la etiqueta
2 - hemos iniciado nuestra clase Juego() con juego = Juego()
Así que solo agreguen eso y continuamos...
Continuamos con el código |
Linea 196 - Esta se encarga de iterar por todos los eventos que pudieran ocurrir y los if-elif se encargan de detectar si alguno se cumple y ejecutar el código que necesitemos.
- La lista de posibles eventos la encuentran aquí: http://www.pygame.org/docs/ref/event.html
Linea 197 - El evento pygame.QUIT que ya venia en la plantilla y explique anteriormente
Linea 200 - El evento pygame.KEYDOWN detecta cuando alguna tecla a sido presionada y con pygame.K_ESCAPE detecta si hemos presionado la tecla "Esc" (Escape)
- La lista de teclas la pueden consultar aquí: http://www.pygame.org/docs/ref/key.html
Linea 203 - El evento pygame.MOUSEBUTTONUP detecta si algún botón del mouse ha sido levantado.
Con juego.obtener_mano_seleccionada verificamos si se selecciono alguna mano, de ser así, llamamos al método principal de nuestra clase Juego() con juego.Jugar() al que si bien recuerdan debemos de pasarle la mano en forma de String(nombre de la mano) que esta seleccionada y eso lo hacemos con juego.obtener_mano_seleccionada().tipo_mano()
Linea 207 - le digo a todas las manos que no están siendo seleccionadas, esto para evitar errores a la hora de estarlas seleccionando (cuando terminemos ejecuta el juego quitando estas 2 líneas para que veas a lo que me refiero).
Excelente, ya estamos a 2 líneas de terminar... entiendo que todos estos conceptos son muy difíciles de asimilar en un principio, pero la única manera de terminar entendiendo todo esto es seguir practicando, no te desilusiones por no entenderlo, de momento yo también me sentí muchas veces así y quería dejarlo todo, pero seguí practicando y ahora lo entiendo todo, después de todo este es mi tutorial =)
Bien, solo nos queda agregar las líneas 213 y 218; juego.actualizar() y juego.dibujar(pantalla)
No se te ocurra poner la segunda línea arriba de pantalla.fill(NEGRO), si haces esto lo único que veras es el fondo negro ya que primero estarías dibujando el juego y después borrar la pantalla. Todo debe de tener su orden!
LISTO!!! Si hiciste todo bien y ejecutas el código, tu juego deberá funcionar como debe.
Les dejo el código final para su descarga aquí en caso de que hayan tenido algún problema y quieran comparar:
https://www.dropbox.com/s/3oqvap7qi9o4u7l/PSPTL%20final.py?dl=1
Demo del Juego...
Espero que esto le sirva de algo a alguien. Saludos
Autor: Salvador Ramirez
Seguir en Google +
-
-
Me alegro. Gracias por visitar el blog 😉
-
-
hola! hice todo tal cual el tutorial lo dice me aparece el siguiente error: File "C:Archivos de programaSublime Text 2PSPLT.py", line 58
self.image = self.copia_imagen
^
IndentationError: expected an indented block
[Finished in 0.5s with exit code 1]Podrias darme una mano para solucionarlo?
muchas gracias y saludos. Santiago-
Hola es un problema de identacion, o sea de sangria.
-
Deja una respuesta
Gracias, me sirvió.