目录
1. 项目概述
2048是一款风靡全球的数字益智游戏,玩家通过滑动方向键合并相同数字,最终目标是合成"2048"这个数字。本文将使用Python的Pygame库实现该游戏的图形化版本,包含分数统计、动画效果和游戏结束判断等核心功能。
2. 开发环境
-
Python 3.8+
-
Pygame 2.0+
-
任意代码编辑器(推荐VS Code/PyCharm)
安装依赖:
pip install pygame
3. 核心代码
游戏关键的代码如下
3.1 网格初始化
使用4x4二维数组存储数字信息,0表示空位:
self.grid = [[0]*4 for _ in range(4)]
3.2 数字生成逻辑
每次操作后在随机空位生成2或4:
def add_new_number(self):
empty_cells = [(i,j) for i in range(4) for j in range(4) 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
3.3 移动与合并算法
以左移为例的合并逻辑:
def move_row_left(row):
# 移除0并合并相邻相同数字
new_row = [i for i in row if i != 0]
for i in range(len(new_row)-1):
if new_row[i] == new_row[i+1]:
new_row[i] *= 2
new_row[i+1] = 0
self.score += new_row[i]
new_row = [i for i in new_row if i != 0]
return new_row + [0]*(4-len(new_row))
其他方向通过矩阵转置/反转复用左移逻辑。
4. 图形界面设计
4.1 颜色方案
可以自行更换
COLORS = {
0: (204, 192, 179),
2: (238, 228, 218),
4: (237, 224, 200),
8: (242, 177, 121),
16: (245, 149, 99),
32: (246, 124, 95),
64: (246, 94, 59),
128: (237, 207, 114),
256: (237, 204, 97),
512: (237, 200, 80),
1024: (237, 197, 63),
2048: (237, 194, 46),
}
4.2 界面元素
-
600x700像素窗口
-
网格间距10像素
-
分数显示区域
-
数字块渐变色设计
# 常量配置
WIDTH = 450
HEIGHT = 550
TILE_SIZE = 100
PADDING = 10
4.3 动画效果
使用线性插值实现滑动动画:
def draw_tiles(self):
for i in range(4):
for j in range(4):
value = self.grid[i][j]
if value != 0:
# 计算动画位置
x = j*TILE_SIZE + (j+1)*PADDING
y = i*TILE_SIZE + (i+1)*PADDING
pygame.draw.rect(screen, COLORS[value], (x,y,TILE_SIZE,TILE_SIZE))
# 绘制数字...
5. 代码结构说明
-
Game2048
类:封装游戏逻辑-
move()
:处理移动操作 -
is_game_over()
:判断游戏结束 -
reset()
:重置游戏状态
-
-
主循环:处理事件和渲染
6. 完整代码
方向键控制移动,R键重新开始,ESC退出游戏。当网格填满且无法合并时游戏结束。
import pygame
import random
import sys
# 常量配置
WIDTH = 450
HEIGHT = 550
TILE_SIZE = 100
PADDING = 10
COLORS = {
0: (204, 192, 179),
2: (238, 228, 218),
4: (237, 224, 200),
8: (242, 177, 121),
16: (245, 149, 99),
32: (246, 124, 95),
64: (246, 94, 59),
128: (237, 207, 114),
256: (237, 204, 97),
512: (237, 200, 80),
1024: (237, 197, 63),
2048: (237, 194, 46),
}
class Game2048:
def __init__(self):
self.grid = [[0] * 4 for _ in range(4)]
self.score = 0
self.high_score = 0
self.add_new_number()
self.add_new_number()
def add_new_number(self):
empty_cells = [(i, j) for i in range(4) for j in range(4) 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 move(self, direction):
moved = False
original_grid = [row.copy() for row in self.grid]
if direction == 'left':
for i in range(4):
new_row = self.move_row_left(self.grid[i])
if new_row != self.grid[i]:
moved = True
self.grid[i] = new_row
elif direction == 'right':
for i in range(4):
new_row = self.move_row_right(self.grid[i])
if new_row != self.grid[i]:
moved = True
self.grid[i] = new_row
elif direction == 'up':
self.grid = [list(row) for row in zip(*self.grid)]
for i in range(4):
new_row = self.move_row_left(self.grid[i])
if new_row != self.grid[i]:
moved = True
self.grid[i] = new_row
self.grid = [list(row) for row in zip(*self.grid)]
elif direction == 'down':
self.grid = [list(row) for row in zip(*self.grid)]
for i in range(4):
new_row = self.move_row_right(self.grid[i])
if new_row != self.grid[i]:
moved = True
self.grid[i] = new_row
self.grid = [list(row) for row in zip(*self.grid)]
if moved:
self.add_new_number()
self.high_score = max(self.high_score, self.score)
return moved
def move_row_left(self, row):
new_row = [num for num in row if num != 0]
for i in range(len(new_row) - 1):
if new_row[i] == new_row[i + 1]:
new_row[i] *= 2
self.score += new_row[i]
new_row[i + 1] = 0
new_row = [num for num in new_row if num != 0]
return new_row + [0] * (4 - len(new_row))
def move_row_right(self, row):
return self.move_row_left(row[::-1])[::-1]
def is_game_over(self):
# 检查空单元格
if any(0 in row for row in self.grid):
return False
# 检查水平方向可合并
for i in range(4):
for j in range(3):
if self.grid[i][j] == self.grid[i][j + 1]:
return False
# 检查垂直方向可合并
for j in range(4):
for i in range(3):
if self.grid[i][j] == self.grid[i + 1][j]:
return False
return True
def draw_game(screen, game, font):
screen.fill((187, 173, 160))
# 绘制分数
text = font.render(f"Score: {game.score} High Score: {game.high_score}", True, (119, 110, 101))
screen.blit(text, (20, 20))
# 绘制网格
for i in range(4):
for j in range(4):
value = game.grid[i][j]
x = j * (TILE_SIZE + PADDING) + PADDING
y = i * (TILE_SIZE + PADDING) + 80
pygame.draw.rect(screen, COLORS.get(value, (0, 0, 0)),
(x, y, TILE_SIZE, TILE_SIZE))
if value != 0:
text_surface = font.render(str(value), True, (119, 110, 101))
text_rect = text_surface.get_rect(center=(x + TILE_SIZE // 2, y + TILE_SIZE // 2))
screen.blit(text_surface, text_rect)
# 游戏结束提示
if game.is_game_over():
overlay = pygame.Surface((WIDTH, HEIGHT - 80), pygame.SRCALPHA)
overlay.fill((255, 255, 255, 128))
text = font.render("Game Over! Press R to restart", True, (255, 0, 0))
text_rect = text.get_rect(center=(WIDTH // 2, (HEIGHT - 80) // 2 + 40))
overlay.blit(text, text_rect)
screen.blit(overlay, (0, 80))
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("2048")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 36)
game = Game2048()
while True:
draw_game(screen, game, font)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == pygame.K_r:
game = Game2048()
elif event.key == pygame.K_LEFT:
game.move('left')
elif event.key == pygame.K_RIGHT:
game.move('right')
elif event.key == pygame.K_UP:
game.move('up')
elif event.key == pygame.K_DOWN:
game.move('down')
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__":
main()
7. 总结与扩展
本实现完整还原了2048的核心玩法,可以通过以下方式扩展:
-
添加音效和更流畅的动画
-
实现撤销功能
-
增加AI自动求解模块
-
支持不同尺寸的网格(5x5、6x6)
通过这个项目,可以学习到:
-
Pygame的基本使用
-
二维数组操作技巧
-
游戏状态管理
-
方向键事件处理