使用 Pygame 构建井字棋游戏

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

本项目将指导你完成使用 Pygame 创建井字棋游戏的步骤。井字棋是一款双人游戏,目标是让你的三个符号在水平、垂直或对角线上连成一排。在本项目中,你将学习如何设置游戏窗口、绘制游戏棋盘、处理玩家和 AI 的移动以及确定获胜者。在本项目结束时,你将拥有一个功能齐全的井字棋游戏,可以与 AI 对手对战。

👀 预览

使用 Pygame 的井字棋

🎯 任务

在本项目中,你将学习:

  • 如何创建项目文件并导入必要的库
  • 如何初始化 PyGame 并设置游戏窗口
  • 如何定义符号、颜色和游戏状态
  • 如何定义按钮属性并创建辅助函数
  • 如何创建主游戏循环并实现辅助函数
  • 如何在主游戏循环中填充其余代码

🏆 成果

完成本项目后,你将能够:

  • 使用 Pygame 创建图形化游戏
  • 使用 Pygame 在窗口上绘制图形
  • 处理用户输入并更新游戏状态
  • 实现游戏逻辑,如检查获胜条件
  • 创建游戏循环以保持游戏运行

创建项目文件

首先,创建一个名为 tic_tac_toe.py 的新文件。在你喜欢的文本编辑器中打开该文件。

cd ~/project
touch tic_tac_toe.py
✨ 查看解决方案并练习

导入必要的库

tic_tac_toe.py 中,导入必要的库:pygamerandom。这些库将分别用于处理游戏图形和生成随机的 AI 移动。

import pygame
import random

使用以下命令安装 pygame 库:

sudo pip install pygame
✨ 查看解决方案并练习

初始化 PyGame 并设置游戏窗口

tic_tac_toe.py 中,使用 pygame.init() 初始化 PyGame。然后,通过定义窗口宽度和高度、背景颜色、线条颜色以及单元格大小来设置游戏窗口。此外,创建一个具有指定宽度和高度的 PyGame 窗口,并设置窗口标题。

pygame.init()

WIDTH = 600
HEIGHT = 600
BACKGROUND_COLOR = (40, 40, 40)
LINE_COLOR = (70, 70, 70)
CELL_SIZE = WIDTH // 3

win = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tic-Tac-Toe")
✨ 查看解决方案并练习

定义符号和颜色

tic_tac_toe.py 中,定义玩家和 AI 的符号及颜色。这些符号和颜色将用于在游戏棋盘上绘制玩家和 AI 的落子。

PLAYER_SYMBOL = "X"
AI_SYMBOL = "O"
PLAYER_COLOR = (0, 255, 0)
AI_COLOR = (255, 0, 0)
EMPTY_COLOR = (0, 0, 0)
✨ 查看解决方案并练习

定义游戏状态

tic_tac_toe.py 中,定义初始游戏状态。这包括游戏棋盘、当前轮到谁(“玩家”或“AI”)、一个表示游戏是否结束的标志,以及游戏的获胜者。

board = [["" for _ in range(3)] for _ in range(3)]
turn = "player"
game_over = False
winner = None
✨ 查看解决方案并练习

定义按钮属性

tic_tac_toe.py 中,定义重置按钮的属性,包括按钮宽度、高度、颜色、文本颜色和字体大小。此外,使用 pygame.Rect 类创建一个 reset_button_rect 对象,以表示按钮的位置和大小。

BUTTON_WIDTH = 200
BUTTON_HEIGHT = 50
BUTTON_COLOR = (50, 50, 50)
BUTTON_TEXT_COLOR = (255, 255, 255)
BUTTON_FONT = pygame.font.Font(None, 30)

reset_button_rect = pygame.Rect(
    (WIDTH - BUTTON_WIDTH) // 2,
    (HEIGHT - BUTTON_HEIGHT) // 2,
    BUTTON_WIDTH,
    BUTTON_HEIGHT,
)
✨ 查看解决方案并练习

创建辅助函数

tic_tac_toe.py 中,定义几个在整个游戏中都会用到的辅助函数。

  • draw_board():此函数将在窗口上绘制游戏棋盘。

  • draw_symbols():此函数将在游戏棋盘上绘制玩家和 AI 的符号。

  • is_board_full():此函数将检查游戏棋盘是否已满。

  • is_winner():此函数将检查是否有玩家赢得了游戏。

  • make_move():此函数将在游戏棋盘上进行一步操作。

  • player_move():此函数将处理玩家的操作。

  • ai_move():此函数将处理 AI 的操作。

  • check_game_over():此函数将检查游戏是否结束。

  • draw_winner():此函数将在窗口上绘制获胜者消息。

  • draw_reset_button():此函数将在窗口上绘制重置按钮。

  • reset_game():此函数将重置游戏状态。

## 辅助函数
def draw_board():
    ## 绘制游戏棋盘
    pass

def draw_symbols():
    ## 在游戏棋盘上绘制玩家和 AI 的符号
    pass

def is_board_full():
    ## 检查游戏棋盘是否已满
    pass

def is_winner(symbol):
    ## 检查是否有玩家赢得了游戏
    pass

def make_move(x, y, symbol):
    ## 在游戏棋盘上进行一步操作
    pass

def player_move():
    ## 处理玩家的操作
    pass

def ai_move():
    ## 处理 AI 的操作
    pass

def check_game_over():
    ## 检查游戏是否结束
    pass

def draw_winner():
    ## 在窗口上绘制获胜者消息
    pass

def draw_reset_button():
    ## 在窗口上绘制重置按钮
    pass

def reset_game():
    ## 重置游戏状态
    pass
✨ 查看解决方案并练习

创建主游戏循环

tic_tac_toe.py 中,使用 while 循环创建主游戏循环。这个循环会一直运行,直到用户关闭游戏窗口。在游戏循环内部,处理用户的输入事件并相应地更新游戏状态。

## 主游戏循环
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if reset_button_rect.collidepoint(event.pos):
                reset_game()
            elif not game_over and turn == "player":
                player_move()

    if not game_over and turn == "ai":
        ai_move()
        check_game_over()

    draw_board()
    draw_symbols()

    if game_over:
        draw_winner()
        draw_reset_button()

    pygame.display.flip()

## 退出游戏
pygame.quit()
✨ 查看解决方案并练习

实现辅助函数

现在,让我们实现之前定义的辅助函数。首先完成 draw_board() 函数。这个函数将通过使用 pygame.draw.line() 函数绘制垂直线和水平线,在窗口上绘制游戏棋盘。

## 辅助函数
def draw_board():
    win.fill(BACKGROUND_COLOR)

    ## 绘制垂直线
    for x in range(1, 3):
        pygame.draw.line(
            win, LINE_COLOR, (CELL_SIZE * x, 0), (CELL_SIZE * x, HEIGHT), 2
        )

    ## 绘制水平线
    for y in range(1, 3):
        pygame.draw.line(win, LINE_COLOR, (0, CELL_SIZE * y), (WIDTH, CELL_SIZE * y), 2)
✨ 查看解决方案并练习

实现其余辅助函数

接下来,实现其余的辅助函数:draw_symbols()is_board_full()is_winner()make_move()player_move()ai_move()check_game_over()draw_winner()draw_reset_button()reset_game()

## 辅助函数
def draw_symbols():
    for x in range(3):
        for y in range(3):
            symbol = board[x][y]
            if symbol == PLAYER_SYMBOL:
                color = PLAYER_COLOR
            elif symbol == AI_SYMBOL:
                color = AI_COLOR
            else:
                color = EMPTY_COLOR
            if symbol!= "":
                pygame.draw.circle(
                    win,
                    color,
                    (x * CELL_SIZE + CELL_SIZE // 2, y * CELL_SIZE + CELL_SIZE // 2),
                    CELL_SIZE // 2 - 10,
                    2,
                )

def is_board_full():
    for row in board:
        if "" in row:
            return False
    return True

def is_winner(symbol):
    for row in board:
        if all(cell == symbol for cell in row):
            return True
    for col in range(3):
        if all(board[row][col] == symbol for row in range(3)):
            return True
    if all(board[i][i] == symbol for i in range(3)):
        return True
    if all(board[i][2 - i] == symbol for i in range(3)):
        return True
    return False

def make_move(x, y, symbol):
    if board[x][y] == "":
        board[x][y] = symbol
        return True
    return False

def player_move():
    global turn
    mouse_pos = pygame.mouse.get_pos()
    cell_x = mouse_pos[0] // CELL_SIZE
    cell_y = mouse_pos[1] // CELL_SIZE

    if make_move(cell_x, cell_y, PLAYER_SYMBOL):
        turn = "ai"

def ai_move():
    global turn
    empty_cells = []
    for x in range(3):
        for y in range(3):
            if board[x][y] == "":
                empty_cells.append((x, y))

    if empty_cells:
        x, y = random.choice(empty_cells)
        make_move(x, y, AI_SYMBOL)

    turn = "player"

def check_game_over():
    global game_over, winner
    if is_winner(PLAYER_SYMBOL):
        game_over = True
        return "player"
    elif is_winner(AI_SYMBOL):
        game_over = True
        return "ai"
    elif is_board_full():
        game_over = True
        return "tie"
    return None

def draw_winner():
    font = pygame.font.Font(None, 50)
    if winner == "player":
        text = font.render("玩家获胜!", True, PLAYER_COLOR)
    elif winner == "ai":
        text = font.render("AI 获胜!", True, AI_COLOR)
    else:
        text = font.render("平局!", True, (255, 255, 255))
    text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 3))
    win.blit(text, text_rect)

def draw_reset_button():
    pygame.draw.rect(win, BUTTON_COLOR, reset_button_rect)
    button_text = BUTTON_FONT.render("重置", True, BUTTON_TEXT_COLOR)
    button_text_rect = button_text.get_rect(center=reset_button_rect.center)
    win.blit(button_text, button_text_rect)

def reset_game():
    global board, turn, game_over, winner
    board = [["" for _ in range(3)] for _ in range(3)]
    turn = "玩家"
    game_over = False
    winner = None

在上述代码中,draw_symbols() 函数将在棋盘上绘制符号。is_board_full() 函数将检查棋盘是否已满。is_winner() 函数将检查给定符号是否赢得了游戏。make_move() 函数将在棋盘上进行一步操作。player_move() 函数将处理玩家的操作。ai_move() 函数将处理 AI 的操作。check_game_over() 函数将检查游戏是否结束。draw_winner() 函数将绘制获胜者消息。draw_reset_button() 函数将绘制重置按钮。reset_game() 函数将重置游戏。

✨ 查看解决方案并练习

补全剩余代码

最后,在主游戏循环中补全剩余代码,以便在适当的位置调用辅助函数。这包括调用 draw_board()draw_symbols() 函数来绘制游戏棋盘和符号,调用 check_game_over() 函数来检查游戏是否结束,以及分别调用 draw_winner()draw_reset_button() 函数来绘制获胜者消息和重置按钮。

## 主游戏循环
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if reset_button_rect.collidepoint(event.pos):
                reset_game()
            elif not game_over and turn == "player":
                player_move()

    if not game_over and turn == "ai":
        ai_move()
        winner = check_game_over()

    draw_board()
    draw_symbols()

    if game_over:
        draw_winner()
        draw_reset_button()

    pygame.display.flip()

## 退出游戏
pygame.quit()

使用以下命令运行游戏:

python tic_tac_toe.py
tic tac toe game screenshot
✨ 查看解决方案并练习

总结

恭喜你!你已经成功使用 Pygame 创建了一个井字棋游戏。在这个项目中,你学习了如何设置游戏窗口、绘制游戏棋盘、处理玩家和 AI 的移动以及确定获胜者。你还学习了如何实现辅助函数来简化代码并使其更具模块化。