Este artículo lo guiará y le dará una idea básica para diseñar un juego Tic Tac Toe usando la biblioteca pygame de Python. Pygame es un conjunto multiplataforma de módulos Python diseñados para escribir videojuegos. Incluye gráficos por computadora y bibliotecas de sonido diseñadas para usarse con el lenguaje de programación Python. Dividamos la tarea en cinco partes:
- Importación de las bibliotecas requeridas y configuración de las variables globales requeridas.
- Diseñar la función de visualización del juego, que establecerá una plataforma para que otros componentes se muestren en la pantalla.
- Algoritmo principal de ganar y empate
- Obtener la entrada del usuario y mostrar la «X» o la «O» en la posición adecuada donde el usuario ha hecho clic con el mouse.
- Ejecutar un bucle infinito e incluir en él los métodos definidos.
Nota: Los archivos PNG necesarios se pueden descargar a continuación:
Importación de las bibliotecas requeridas y configuración de las variables globales requeridas
Vamos a usar la biblioteca pygame, time y sys de Python. La biblioteca de tiempo se usa para realizar un seguimiento del tiempo y el método sleep() que vamos a usar dentro de nuestro código. Eche un vistazo al código a continuación.
Python3
# importing the required libraries import pygame as pg import sys import time from pygame.locals import * # declaring the global variables # for storing the 'x' or 'o' # value as character XO = 'x' # storing the winner's value at # any instant of code winner = None # to check if the game is a draw draw = None # to set width of the game window width = 400 # to set height of the game window height = 400 # to set background color of the # game window white = (255, 255, 255) # color of the straightlines on that # white game board, dividing board # into 9 parts line_color = (0, 0, 0) # setting up a 3 * 3 board in canvas board = [[None]*3, [None]*3, [None]*3]
Diseño de la pantalla del juego
Esta es la parte más complicada, que tiene la mayor importancia en el desarrollo del juego. Podemos usar el método display.set_mode() para configurar nuestra ventana de visualización. Esto toma tres argumentos, el primero es una tupla que tiene (ancho, alto) de la pantalla que queremos que sea, los otros dos argumentos son profundidad y fps respectivamente. display.set_caption() , establece un título en la etiqueta de nombre de nuestra pantalla. pg.image.load() es un método útil para cargar las imágenes de fondo para personalizar la visualización. Este método toma el nombre del archivo como argumento junto con la extensión. Hay un pequeño problema con image.load(), carga la imagen como un objeto de Python en su tamaño nativo, que puede no estar optimizado junto con la pantalla. Así que usamos otro método en pygame conocido comopg.transform.escala() . Este método toma dos argumentos, uno es el nombre del objeto de la imagen y el otro es una tupla que tiene (ancho, alto), a la que queremos escalar nuestra imagen. Finalmente nos dirigimos a la primera función, game_initiating_window() . En la primera línea hay una función screen.blit() . La pantalla es la función de Python y blit es el método que permite que pygame muestre algo sobre otra cosa. Aquí, el objeto de imagen se ha mostrado sobre la pantalla, que inicialmente se configuró en blanco. pg.display.update() es otra función importante en el desarrollo de juegos. Actualiza la visualización de nuestra ventana cuando se llama. Pygame también nos permite dibujar objetos geométricos como líneas, círculos, etc. En este proyecto hemos utilizadopg.draw.line() método que toma cinco argumentos, a saber: (pantalla, color de línea, punto de inicio, punto final, ancho) . Esto implica un poco de geometría de coordenadas para dibujar las líneas correctamente. Esto no es suficiente. En cada actualización de la pantalla, necesitamos saber el estado del juego, ya sea que gane o pierda. draw_status() nos ayuda a mostrar otra ventana de 100 piezas en la parte inferior de la ventana principal, que actualiza el estado con cada clic del usuario.
Python3
# initializing the pygame window pg.init() # setting fps manually fps = 30 # this is used to track time CLOCK = pg.time.Clock() # this method is used to build the # infrastructure of the display screen = pg.display.set_mode((width, height + 100), 0, 32) # setting up a nametag for the # game window pg.display.set_caption("My Tic Tac Toe") # loading the images as python object initiating_window = pg.image.load("modified_cover.png") x_img = pg.image.load("X_modified.png") y_img = pg.image.load("o_modified.png") # resizing images initiating_window = pg.transform.scale(initiating_window, (width, height + 100)) x_img = pg.transform.scale(x_img, (80, 80)) o_img = pg.transform.scale(y_img, (80, 80)) def game_initiating_window(): # displaying over the screen screen.blit(initiating_window, (0, 0)) # updating the display pg.display.update() time.sleep(3) screen.fill(white) # drawing vertical lines pg.draw.line(screen, line_color, (width / 3, 0), (width / 3, height), 7) pg.draw.line(screen, line_color, (width / 3 * 2, 0), (width / 3 * 2, height), 7) # drawing horizontal lines pg.draw.line(screen, line_color, (0, height / 3), (width, height / 3), 7) pg.draw.line(screen, line_color, (0, height / 3 * 2), (width, height / 3 * 2), 7) draw_status() def draw_status(): # getting the global variable draw # into action global draw if winner is None: message = XO.upper() + "'s Turn" else: message = winner.upper() + " won !" if draw: message = "Game Draw !" # setting a font object font = pg.font.Font(None, 30) # setting the font properties like # color and width of the text text = font.render(message, 1, (255, 255, 255)) # copy the rendered message onto the board # creating a small block at the bottom of the main display screen.fill ((0, 0, 0), (0, 400, 500, 100)) text_rect = text.get_rect(center =(width / 2, 500-50)) screen.blit(text, text_rect) pg.display.update()
Algoritmo principal
El algoritmo principal tiene un enfoque sencillo. Un usuario puede ganar por filas, por columnas y en diagonal. Entonces, al usar una array multidimensional, podemos configurar las condiciones fácilmente.
Python3
def check_win(): global board, winner, draw # checking for winning rows for row in range(0, 3): if((board[row][0] == board[row][1] == board[row][2]) and (board [row][0] is not None)): winner = board[row][0] pg.draw.line(screen, (250, 0, 0), (0, (row + 1)*height / 3 -height / 6), (width, (row + 1)*height / 3 - height / 6 ), 4) break # checking for winning columns for col in range(0, 3): if((board[0][col] == board[1][col] == board[2][col]) and (board[0][col] is not None)): winner = board[0][col] pg.draw.line (screen, (250, 0, 0), ((col + 1)* width / 3 - width / 6, 0), \ ((col + 1)* width / 3 - width / 6, height), 4) break # check for diagonal winners if (board[0][0] == board[1][1] == board[2][2]) and (board[0][0] is not None): # game won diagonally left to right winner = board[0][0] pg.draw.line (screen, (250, 70, 70), (50, 50), (350, 350), 4) if (board[0][2] == board[1][1] == board[2][0]) and (board[0][2] is not None): # game won diagonally right to left winner = board[0][2] pg.draw.line (screen, (250, 70, 70), (350, 50), (50, 350), 4) if(all([all(row) for row in board]) and winner is None ): draw = True draw_status()
Obtener la entrada del usuario y mostrar la «X» o la «O»
Esta parte trata de una visualización del tablero y un poco de geometría de coordenadas. drawXO() toma dos argumentos fila y columna. En primer lugar, debemos configurar la posición geométrica correcta para colocar la imagen de X y la imagen de O que hemos almacenado como dos objetos de Python «x_img» e «y_img» respectivamente. Eche un vistazo al código para una comprensión adecuada. user_click() es una función que hemos diseñado para obtener la entrada de un clic del mouse del usuario. Imagina que has hecho clic en una de las nueve partes (cuadros divididos por las líneas que hemos dibujado en horizontal y en vertical), esta función definirá la coordenada de la posición en la que has hecho clic. pg.mouse.get_pos()obtiene la coordenada x y la coordenada y del clic del mouse del usuario y devuelve una tupla. Dependiendo de (x, y) podemos definir la fila exacta y la columna exacta donde el usuario ha hecho clic. Finalmente, cuando tenemos la fila y la columna, pasamos estos dos como argumentos a la función dibujarXO(fila, columna) para dibujar la imagen de ‘X’ o la imagen de ‘O’ en la posición deseada del usuario en el juego. pantalla.
Python3
def drawXO(row, col): global board, XO # for the first row, the image # should be pasted at a x coordinate # of 30 from the left margin if row == 1: posx = 30 # for the second row, the image # should be pasted at a x coordinate # of 30 from the game line if row == 2: # margin or width / 3 + 30 from # the left margin of the window posx = width / 3 + 30 if row == 3: posx = width / 3 * 2 + 30 if col == 1: posy = 30 if col == 2: posy = height / 3 + 30 if col == 3: posy = height / 3 * 2 + 30 # setting up the required board # value to display board[row-1][col-1] = XO if(XO == 'x'): # pasting x_img over the screen # at a coordinate position of # (pos_y, posx) defined in the # above code screen.blit(x_img, (posy, posx)) XO = 'o' else: screen.blit(o_img, (posy, posx)) XO = 'x' pg.display.update() def user_click(): # get coordinates of mouse click x, y = pg.mouse.get_pos() # get column of mouse click (1-3) if(x<width / 3): col = 1 elif (x<width / 3 * 2): col = 2 elif(x<width): col = 3 else: col = None # get row of mouse click (1-3) if(y<height / 3): row = 1 elif (y<height / 3 * 2): row = 2 elif(y<height): row = 3 else: row = None # after getting the row and col, # we need to draw the images at # the desired positions if(row and col and board[row-1][col-1] is None): global XO drawXO(row, col) check_win()
Ejecutar un bucle infinito
Este es el último paso importante para ejecutar nuestro juego infinitamente hasta que el usuario haga clic en salir . Antes de ejecutar un ciclo infinito, debemos configurar una función que pueda restablecer todos los valores y parámetros globales a los valores iniciales para un nuevo comienzo del juego. reset_game() se usa para este propósito. Restablece el valor de la placa a 3 * 3 Ninguno de nuevo e inicializa los parámetros globales. En el desarrollo del juego, cada acción del jugador es un evento . Ya sea que haga clic en la ventana o haga clic en el icono de salir/cerrar. Para obtener estos eventos como un objeto, pygame tiene un método integrado que se usa como pg.event.get() . Si el tipo de evento es «QUIT», usamos la biblioteca sys de Python para salir del juego. Pero si se presiona el mouse, el event.get()devolverá «MOUSEBUTTONDOWN» y nuestra llamada a user_click() conoce la coordenada exacta del tablero donde el usuario ha hecho clic. En todo el código, hemos utilizado el método .sleep() para pausar nuestro juego a veces y hacerlo fácil de usar y fluido.
Python3
def reset_game(): global board, winner, XO, draw time.sleep(3) XO = 'x' draw = False game_initiating_window() winner = None board = [[None]*3, [None]*3, [None]*3] game_initiating_window() while(True): for event in pg.event.get(): if event.type == QUIT: pg.quit() sys.exit() elif event.type is MOUSEBUTTONDOWN: user_click() if(winner or draw): reset_game() pg.display.update() CLOCK.tick(fps)
El código completo:
Python3
# importing the required libraries import pygame as pg import sys import time from pygame.locals import * # declaring the global variables # for storing the 'x' or 'o' # value as character XO = 'x' # storing the winner's value at # any instant of code winner = None # to check if the game is a draw draw = None # to set width of the game window width = 400 # to set height of the game window height = 400 # to set background color of the # game window white = (255, 255, 255) # color of the straightlines on that # white game board, dividing board # into 9 parts line_color = (0, 0, 0) # setting up a 3 * 3 board in canvas board = [[None]*3, [None]*3, [None]*3] # initializing the pygame window pg.init() # setting fps manually fps = 30 # this is used to track time CLOCK = pg.time.Clock() # this method is used to build the # infrastructure of the display screen = pg.display.set_mode((width, height + 100), 0, 32) # setting up a nametag for the # game window pg.display.set_caption("My Tic Tac Toe") # loading the images as python object initiating_window = pg.image.load("modified_cover.png") x_img = pg.image.load("X_modified.png") y_img = pg.image.load("o_modified.png") # resizing images initiating_window = pg.transform.scale(initiating_window, (width, height + 100)) x_img = pg.transform.scale(x_img, (80, 80)) o_img = pg.transform.scale(y_img, (80, 80)) def game_initiating_window(): # displaying over the screen screen.blit(initiating_window, (0, 0)) # updating the display pg.display.update() time.sleep(3) screen.fill(white) # drawing vertical lines pg.draw.line(screen, line_color, (width / 3, 0), (width / 3, height), 7) pg.draw.line(screen, line_color, (width / 3 * 2, 0), (width / 3 * 2, height), 7) # drawing horizontal lines pg.draw.line(screen, line_color, (0, height / 3), (width, height / 3), 7) pg.draw.line(screen, line_color, (0, height / 3 * 2), (width, height / 3 * 2), 7) draw_status() def draw_status(): # getting the global variable draw # into action global draw if winner is None: message = XO.upper() + "'s Turn" else: message = winner.upper() + " won !" if draw: message = "Game Draw !" # setting a font object font = pg.font.Font(None, 30) # setting the font properties like # color and width of the text text = font.render(message, 1, (255, 255, 255)) # copy the rendered message onto the board # creating a small block at the bottom of the main display screen.fill ((0, 0, 0), (0, 400, 500, 100)) text_rect = text.get_rect(center =(width / 2, 500-50)) screen.blit(text, text_rect) pg.display.update() def check_win(): global board, winner, draw # checking for winning rows for row in range(0, 3): if((board[row][0] == board[row][1] == board[row][2]) and (board [row][0] is not None)): winner = board[row][0] pg.draw.line(screen, (250, 0, 0), (0, (row + 1)*height / 3 -height / 6), (width, (row + 1)*height / 3 - height / 6 ), 4) break # checking for winning columns for col in range(0, 3): if((board[0][col] == board[1][col] == board[2][col]) and (board[0][col] is not None)): winner = board[0][col] pg.draw.line (screen, (250, 0, 0), ((col + 1)* width / 3 - width / 6, 0), \ ((col + 1)* width / 3 - width / 6, height), 4) break # check for diagonal winners if (board[0][0] == board[1][1] == board[2][2]) and (board[0][0] is not None): # game won diagonally left to right winner = board[0][0] pg.draw.line (screen, (250, 70, 70), (50, 50), (350, 350), 4) if (board[0][2] == board[1][1] == board[2][0]) and (board[0][2] is not None): # game won diagonally right to left winner = board[0][2] pg.draw.line (screen, (250, 70, 70), (350, 50), (50, 350), 4) if(all([all(row) for row in board]) and winner is None ): draw = True draw_status() def drawXO(row, col): global board, XO # for the first row, the image # should be pasted at a x coordinate # of 30 from the left margin if row == 1: posx = 30 # for the second row, the image # should be pasted at a x coordinate # of 30 from the game line if row == 2: # margin or width / 3 + 30 from # the left margin of the window posx = width / 3 + 30 if row == 3: posx = width / 3 * 2 + 30 if col == 1: posy = 30 if col == 2: posy = height / 3 + 30 if col == 3: posy = height / 3 * 2 + 30 # setting up the required board # value to display board[row-1][col-1] = XO if(XO == 'x'): # pasting x_img over the screen # at a coordinate position of # (pos_y, posx) defined in the # above code screen.blit(x_img, (posy, posx)) XO = 'o' else: screen.blit(o_img, (posy, posx)) XO = 'x' pg.display.update() def user_click(): # get coordinates of mouse click x, y = pg.mouse.get_pos() # get column of mouse click (1-3) if(x<width / 3): col = 1 elif (x<width / 3 * 2): col = 2 elif(x<width): col = 3 else: col = None # get row of mouse click (1-3) if(y<height / 3): row = 1 elif (y<height / 3 * 2): row = 2 elif(y<height): row = 3 else: row = None # after getting the row and col, # we need to draw the images at # the desired positions if(row and col and board[row-1][col-1] is None): global XO drawXO(row, col) check_win() def reset_game(): global board, winner, XO, draw time.sleep(3) XO = 'x' draw = False game_initiating_window() winner = None board = [[None]*3, [None]*3, [None]*3] game_initiating_window() while(True): for event in pg.event.get(): if event.type == QUIT: pg.quit() sys.exit() elif event.type is MOUSEBUTTONDOWN: user_click() if(winner or draw): reset_game() pg.display.update() CLOCK.tick(fps)
Producción:
Publicación traducida automáticamente
Artículo escrito por AbhijitTripathy y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA