首页 > Python资料 博客日记

用 Python 实现经典的 2048 游戏:一步步带你打造属于你的小游戏!

2025-01-05 21:00:05Python资料围观11

文章用 Python 实现经典的 2048 游戏:一步步带你打造属于你的小游戏!分享给大家,欢迎收藏Python资料网,专注分享技术知识

用 Python 实现经典的 2048 游戏:一步步带你打造属于你的小游戏!(结尾附完整代码)

简介

2048 是一个简单而又令人上瘾的数字拼图游戏。玩家通过滑动方块使相同数字的方块合并,目标是创造出数字 2048!在这篇博客中,我们将用 Python 的 Tkinter 库 从零开始实现这款游戏,涵盖从界面设计到逻辑实现的每一个细节,帮助你全面了解背后的开发思路。

游戏特点

  • 经典玩法:滑动合并相同数字,尽可能达到 2048。
  • 随机生成新数字:每次滑动后随机生成 2 或 4。
  • 直观的图形界面:使用 Tkinter 绘制游戏网格与方块,带来清晰的视觉效果。

开发环境准备

在开始之前,确保你的环境已安装 Python,并包含以下必要库:

pip install tk

Tkinter 是 Python 内置的 GUI 工具包,因此大多数环境无需额外安装。 

项目实现步骤

我们将按照以下步骤构建游戏:

  1. 设计网格界面
  2. 实现核心逻辑
  3. 绑定键盘事件
  4. 添加游戏结束检测
  5. 优化用户体验

1. 设计网格界面

首先,我们定义游戏的基本参数,包括网格大小、方块的尺寸、间距和颜色等。随后,通过 Tkinter 创建一个网格界面,每个格子将用矩形和文本元素表示。

import tkinter as tk
from tkinter import messagebox
import random

# 常量定义
GRID_SIZE = 4  # 网格为 4x4
TILE_SIZE = 100  # 每个方块的像素大小
PADDING = 10  # 方块之间的间距
BACKGROUND_COLOR = "#92877d"
TILE_COLORS = {
    0: "#9e948a", 2: "#eee4da", 4: "#ede0c8",
    8: "#f2b179", 16: "#f59563", 32: "#f67c5f",
    64: "#f65e3b", 128: "#edcf72", 256: "#edcc61",
    512: "#edc850", 1024: "#edc53f", 2048: "#edc22e",
}

# 初始化游戏界面
class Game2048:
    def __init__(self, master):
        self.master = master
        self.master.title("2048")
        self.master.geometry(f"{GRID_SIZE * TILE_SIZE + PADDING * (GRID_SIZE + 1)}x{GRID_SIZE * TILE_SIZE + PADDING * (GRID_SIZE + 1)}")
        self.master.resizable(False, False)
        self.init_grid()
        self.reset_game()

    def init_grid(self):
        """创建 4x4 网格"""
        self.canvas = tk.Canvas(self.master, bg=BACKGROUND_COLOR, bd=0, highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        self.tiles = []
        for i in range(GRID_SIZE):
            row = []
            for j in range(GRID_SIZE):
                x1 = PADDING + j * (TILE_SIZE + PADDING)
                y1 = PADDING + i * (TILE_SIZE + PADDING)
                x2 = x1 + TILE_SIZE
                y2 = y1 + TILE_SIZE
                rect = self.canvas.create_rectangle(x1, y1, x2, y2, fill=TILE_COLORS[0], outline="")
                text = self.canvas.create_text(x1 + TILE_SIZE // 2, y1 + TILE_SIZE // 2, text="", font=("Helvetica", 30), fill="#776e65")
                row.append((rect, text))
            self.tiles.append(row)

 运行效果:运行后你会看到一个 4x4 的灰色网格,每个格子代表一个方块。

 

2. 实现核心逻辑

游戏的逻辑主要包括:

  • 压缩和合并数字:将相邻的数字合并。
  • 滑动方向操作:实现上下左右滑动功能。
  • 随机生成新数字:在空格中随机生成 2 或 4。
压缩与合并

每次滑动操作可以拆分为两部分:压缩(去掉空格)合并(合并相邻的相同数字)

def compress(row):
    """将行向左压缩,去掉 0"""
    new_row = [num for num in row if num != 0]
    new_row += [0] * (GRID_SIZE - len(new_row))
    return new_row

def merge(row):
    """合并相邻相同的数字"""
    for i in range(len(row) - 1):
        if row[i] == row[i + 1] and row[i] != 0:
            row[i] *= 2
            row[i + 1] = 0
    return row
滑动操作

根据方向执行不同操作(上下左右)。

def move_left(grid):
    """左移操作"""
    new_grid = []
    for row in grid:
        compressed_row = compress(row)
        merged_row = merge(compressed_row)
        new_grid.append(compress(merged_row))
    return new_grid
随机生成数字

每次滑动后随机选择一个空格,填入 2 或 4。

def spawn_new_tile(grid):
    """随机生成一个新的数字方块(2 或 4)"""
    empty_cells = [(i, j) for i in range(GRID_SIZE) for j in range(GRID_SIZE) if grid[i][j] == 0]
    if empty_cells:
        i, j = random.choice(empty_cells)
        grid[i][j] = 2 if random.random() < 0.9 else 4

3. 绑定键盘事件

为了让游戏动起来,我们需要捕获用户的按键(上下左右方向键),并根据按键更新网格状态。

def key_press(event):
    """处理键盘输入"""
    key = event.keysym
    if key in ["Up", "Down", "Left", "Right"]:
        if key == "Up":
            game.grid = move_left(rotate_left(game.grid))
            game.grid = rotate_right(game.grid)
        elif key == "Down":
            game.grid = move_left(rotate_right(game.grid))
            game.grid = rotate_left(game.grid)
        elif key == "Left":
            game.grid = move_left(game.grid)
        elif key == "Right":
            game.grid = move_left(reverse_rows(game.grid))
            game.grid = reverse_rows(game.grid)
        spawn_new_tile(game.grid)
        game.update_ui()
        if is_game_over(game.grid):
            messagebox.showinfo("Game Over", "No more moves left!")

4. 添加游戏结束检测

当所有格子都被填满且没有可合并的数字时,游戏结束。

def is_game_over(grid):
    """判断是否还有有效操作"""
    for i in range(GRID_SIZE):
        for j in range(GRID_SIZE):
            if grid[i][j] == 0:  # 空格存在
                return False
            if j + 1 < GRID_SIZE and grid[i][j] == grid[i][j + 1]:  # 横向可合并
                return False
            if i + 1 < GRID_SIZE and grid[i][j] == grid[i + 1][j]:  # 纵向可合并
                return False
    return True

5. 完整代码

将上述代码整合的完整代码如下:运行后即可得到完整的 2048 游戏!

import tkinter as tk
from tkinter import messagebox
import random

# 常量定义
GRID_SIZE = 4
TILE_SIZE = 100
PADDING = 10
BACKGROUND_COLOR = "#92877d"
TILE_COLORS = {
    0: "#9e948a", 2: "#eee4da", 4: "#ede0c8",
    8: "#f2b179", 16: "#f59563", 32: "#f67c5f",
    64: "#f65e3b", 128: "#edcf72", 256: "#edcc61",
    512: "#edc850", 1024: "#edc53f", 2048: "#edc22e",
}

class Game2048:
    def __init__(self, master):
        self.master = master
        self.master.title("2048")
        self.master.geometry(f"{GRID_SIZE * TILE_SIZE + PADDING * (GRID_SIZE + 1)}x{GRID_SIZE * TILE_SIZE + PADDING * (GRID_SIZE + 1)}")
        self.master.resizable(False, False)
        self.init_grid()
        self.reset_game()

    def init_grid(self):
        """初始化网格界面"""
        self.canvas = tk.Canvas(self.master, bg=BACKGROUND_COLOR, bd=0, highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        self.tiles = []
        for i in range(GRID_SIZE):
            row = []
            for j in range(GRID_SIZE):
                x1 = PADDING + j * (TILE_SIZE + PADDING)
                y1 = PADDING + i * (TILE_SIZE + PADDING)
                x2 = x1 + TILE_SIZE
                y2 = y1 + TILE_SIZE
                rect = self.canvas.create_rectangle(x1, y1, x2, y2, fill=TILE_COLORS[0], outline="")
                text = self.canvas.create_text(x1 + TILE_SIZE // 2, y1 + TILE_SIZE // 2, text="", font=("Helvetica", 30), fill="#776e65")
                row.append((rect, text))
            self.tiles.append(row)

    def reset_game(self):
        """重置游戏状态"""
        self.grid = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]
        self.spawn_new_tile()
        self.spawn_new_tile()
        self.update_ui()

    def spawn_new_tile(self):
        """随机生成一个新的数字方块(2 或 4)"""
        empty_cells = [(i, j) for i in range(GRID_SIZE) for j in range(GRID_SIZE) if self.grid[i][j] == 0]
        if empty_cells:
            i, j = random.choice(empty_cells)
            self.grid[i][j] = 2 if random.random() < 0.9 else 4

    def update_ui(self):
        """更新界面显示"""
        for i in range(GRID_SIZE):
            for j in range(GRID_SIZE):
                value = self.grid[i][j]
                rect, text = self.tiles[i][j]
                self.canvas.itemconfig(rect, fill=TILE_COLORS.get(value, TILE_COLORS[2048]))
                self.canvas.itemconfig(text, text=str(value) if value != 0 else "")

def compress(row):
    """将行向左压缩,去掉 0"""
    new_row = [num for num in row if num != 0]
    new_row += [0] * (GRID_SIZE - len(new_row))
    return new_row

def merge(row):
    """合并相邻相同的数字"""
    for i in range(len(row) - 1):
        if row[i] == row[i + 1] and row[i] != 0:
            row[i] *= 2
            row[i + 1] = 0
    return row

def move_left(grid):
    """左移操作"""
    new_grid = []
    for row in grid:
        compressed_row = compress(row)
        merged_row = merge(compressed_row)
        new_grid.append(compress(merged_row))
    return new_grid

def rotate_right(grid):
    """矩阵顺时针旋转 90°"""
    return [list(row) for row in zip(*grid[::-1])]

def rotate_left(grid):
    """矩阵逆时针旋转 90°"""
    return [list(row) for row in zip(*grid)][::-1]

def reverse_rows(grid):
    """矩阵水平翻转"""
    return [row[::-1] for row in grid]

def is_game_over(grid):
    """判断是否还有有效操作"""
    for i in range(GRID_SIZE):
        for j in range(GRID_SIZE):
            if grid[i][j] == 0:  # 空格存在
                return False
            if j + 1 < GRID_SIZE and grid[i][j] == grid[i][j + 1]:  # 横向可合并
                return False
            if i + 1 < GRID_SIZE and grid[i][j] == grid[i + 1][j]:  # 纵向可合并
                return False
    return True

def key_press(event):
    """处理键盘输入"""
    key = event.keysym
    if key in ["Up", "Down", "Left", "Right"]:
        if key == "Up":
            game.grid = move_left(rotate_left(game.grid))
            game.grid = rotate_right(game.grid)
        elif key == "Down":
            game.grid = move_left(rotate_right(game.grid))
            game.grid = rotate_left(game.grid)
        elif key == "Left":
            game.grid = move_left(game.grid)
        elif key == "Right":
            game.grid = move_left(reverse_rows(game.grid))
            game.grid = reverse_rows(game.grid)
        game.spawn_new_tile()
        game.update_ui()
        if is_game_over(game.grid):
            messagebox.showinfo("Game Over", "No more moves left!")

root = tk.Tk()
game = Game2048(root)
root.bind("<Key>", key_press)
root.mainloop()

通过本篇博客,我们从头实现了经典的 2048 游戏。不仅让你掌握了 Tkinter 界面开发,还深入理解了游戏逻辑的实现过程。如果你喜欢这篇博客,请分享给更多的 Python 爱好者吧!


版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐