井字游戏 GUI 在Python中使用 PyGame
这篇文章将指导您并让您了解使用Python的pygame库设计井字游戏的基本思路。 Pygame 是一组用于编写视频游戏的跨平台Python模块。它包括旨在与Python编程语言一起使用的计算机图形和声音库。
让我们将任务分为五个部分:
- 导入所需的库并设置所需的全局变量。
- 设计游戏显示函数,为其他组件在屏幕上显示设置平台。
- 主要的获胜和平局算法
- 获取用户输入并在用户单击鼠标的适当位置显示“X”或“O”。
- 运行一个无限循环,并在其中包含定义的方法。
注意:所需的PNG文件可以在下面下载——
导入所需的库并设置所需的全局变量
我们将使用Python的pygame
、 time
和sys
库。时间库用于跟踪我们将在代码中使用的时间和sleep()
方法。看看下面的代码。
# 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]
设计游戏画面
这是比较棘手的部分,它在游戏开发中至关重要。我们可以使用display.set_mode()方法来设置我们的显示窗口。这需要三个参数,第一个是具有我们想要的显示的(宽度,高度)的元组,另外两个参数分别是深度和 fps。 display.set_caption() ,在我们的显示器的名称标签上设置一个标题。 pg.image.load()是加载背景图像以自定义显示的有用方法。此方法将文件名与扩展名一起作为参数。 image.load()
有一个小问题,它将图像加载为其原生大小的Python对象,这可能不会与显示一起优化。所以我们在 pygame 中使用另一种方法,称为pg.transform.scale() 。这个方法有两个参数,一个是图像对象的名称,另一个是一个具有 (width, height) 的元组,我们希望我们的图像可以缩放到。
最后我们转到第一个函数game_initiating_window() 。在第一行有一个screen.blit()函数。 screen 是Python函数,而 blit 是使 pygame 能够在另一事物上显示某些内容的方法。此处的图像对象已显示在屏幕上,最初设置为白色。 pg.display.update()是游戏开发中的另一个重要函数。它在调用时更新我们窗口的显示。 Pygame 还使我们能够绘制直线、圆等几何对象。在这个项目中,我们使用了 pg.draw.line()方法,该方法接受五个参数,即 - (显示、线条颜色、起点、终点、宽度) .这涉及到一点坐标几何来正确绘制线条。
这还不够。在每次更新显示时,我们都需要知道游戏状态,天气是输是赢。 draw_status()帮助我们在主窗口底部显示另一个 100pc 窗口,在用户每次点击时更新状态。
# 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()
获取用户输入并显示“X”或“O”
这部分处理电路板的可视化和一些坐标几何。 drawXO()接受两个参数 row 和 col。首先,我们必须设置正确的几何位置,将我们存储的 X 图像和 O 图像分别存储为两个Python对象“x_img”和“y_img”。查看代码以获得正确的理解。
user_click()是我们设计的一个函数,用于从用户鼠标单击中获取输入。想象一下,您点击了九个部分之一(框除以我们绘制的水平和垂直线),该函数将定义您单击的位置的坐标。 pg.mouse.get_pos()获取用户鼠标点击的x坐标和y坐标,并返回一个元组。根据 (x, y),我们可以定义用户单击的确切行和确切列。最后,当我们有 row 和 col 时,我们将这两个作为参数传递给函数drawXO(row, col)以在游戏中用户所需的位置绘制“X”或“O”的图像屏幕。
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
运行无限循环
这是无限运行我们的游戏直到用户点击退出的最后一个重要步骤。在运行无限循环之前,我们需要设置一个函数,该函数可以将所有全局值和参数重置为初始值,以便重新开始游戏。
reset_game()用于此目的。它再次将板值重置为 3 * 3 None 值并初始化全局参数。
在游戏开发中,玩家的每一个动作都是一个事件。他是点击窗口还是点击退出/关闭图标。要将这些事件作为对象获取,pygame 有一个用作pg.event.get()的内置方法。如果事件类型为“QUIT”,我们使用Python的 sys 库退出游戏。但是如果按下鼠标, event.get()将返回“MOUSEBUTTONDOWN”,而我们对user_click()的调用恰好知道用户点击的棋盘的确切坐标。
在整个代码中,我们使用了.sleep()
方法来暂停我们的游戏,让游戏变得友好和流畅。
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)
完整代码:
# 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
输出: