

Python,速成心法
敲代码,查资料,问度娘
练习,探索,总结,优化

★★★★★博文创作不易,使用代码的过程中,如有疑问的地方,欢迎大家指正留言交流。喜欢的老铁可以多多点赞+收藏分享+置顶,小红牛在此表示感谢。★★★★★
------★Pygame经典游戏★-------
Python经典游戏:太空飞机大战Space Plane Battle
Pygame经典游戏:坦克大战TankWar+五子棋人机对弈+俄罗斯方块(安排!!)
Pygame经典游戏:微信飞机大战Wechatflying(初级版)
Python经典游戏:走迷宫,好烦呀,我到现在还没有走出去!!
Pygame教程03:文本显示+字体加载+transform方法
Pygame教程04:draw方法绘制矩形、多边形、圆、椭圆、弧线、直线和线条等
Pygame教程05:帧动画原理+边界值检测,让小球来回上下运动
Pygame教程06:Event事件的类型+处理方法+监听鼠标事件
Pygame教程08:使用键盘方向键,控制小球,上下左右移动。
Pygame教程09:font.render文本内容,如何自动换行显示

↓ 源码如下 ↓
# -*- coding: utf-8 -*-# @Author : 小红牛# 微信公众号:wdPythonimport pygameimport randomimport sys# 初始化Pygamepygame.init()# 游戏配置WIDTH, HEIGHT = 450, 550 # 窗口宽度和高度GRID_SIZE = 4 # 4x4网格CELL_SIZE = 80 # 每个格子大小MARGIN = 10 # 格子间距GRID_LEFT = (WIDTH - (GRID_SIZE * CELL_SIZE + (GRID_SIZE - 1) * MARGIN)) // 2GRID_TOP = 120 # 网格顶部Y坐标# 颜色定义 (R, G, B)BG_COLOR = (250, 248, 239) # 背景米色EMPTY_COLOR = (205, 193, 180) # 空格子颜色# 数字对应的格子颜色TILE_COLORS = {0: (205, 193, 180),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),}# 文字颜色 (深色/浅色)DARK_TEXT = (119, 110, 101)LIGHT_TEXT = (249, 246, 242)# 字体设置FONT_LARGE = pygame.font.SysFont("arial", 36, bold=True)FONT_MEDIUM = pygame.font.SysFont("arial", 28, bold=True)FONT_SMALL = pygame.font.SysFont("arial", 24, bold=True)class Game2048:"""2048游戏核心逻辑"""def __init__(self):self.grid = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]self.score = 0self.highscore = 0self.game_over = Falseself.reset() # 初始化网格并添加两个起始数字def reset(self):"""重置游戏(保留最高分)"""self.grid = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]self.score = 0self.game_over = Falseself.add_random_tile() # 第一个数字self.add_random_tile() # 第二个数字def add_random_tile(self):"""在随机空格子添加新数字(2或4),90%概率为2,10%概率为4"""empty_cells = [(r, c) for r in range(GRID_SIZE) for c in range(GRID_SIZE) if self.grid[r][c] == 0]if empty_cells:r, c = random.choice(empty_cells)self.grid[r][c] = 2 if random.random() < 0.9 else 4return Truereturn Falsedef get_max_tile(self):"""获取当前网格中的最大数字"""return max(max(row) for row in self.grid)def update_highscore(self):"""更新最高分"""if self.score > self.highscore:self.highscore = self.scoredef is_game_over(self):"""检查游戏是否结束:没有空格子且任何方向都无法移动"""# 如果有空格,游戏未结束if any(self.grid[r][c] == 0 for r in range(GRID_SIZE) for c in range(GRID_SIZE)):return False# 检查是否还有相邻相同数字可以合并for r in range(GRID_SIZE):for c in range(GRID_SIZE):val = self.grid[r][c]if (c + 1 < GRID_SIZE and self.grid[r][c + 1] == val) or \(r + 1 < GRID_SIZE and self.grid[r + 1][c] == val):return Falsereturn True# ---------- 移动和合并核心算法 ----------@staticmethoddef _merge_line(line):"""合并一行(向左),返回新行和本次合并获得的分数"""# 过滤掉0,得到非零数字列表filtered = [num for num in line if num != 0]new_line = []score_gain = 0skip = Falsefor i in range(len(filtered)):if skip:skip = Falsecontinue# 如果下一个数字存在且相等,合并if i + 1 < len(filtered) and filtered[i] == filtered[i + 1]:merged = filtered[i] * 2new_line.append(merged)score_gain += mergedskip = Trueelse:new_line.append(filtered[i])# 补零至长度为GRID_SIZEnew_line += [0] * (GRID_SIZE - len(new_line))return new_line, score_gaindef _move_left(self):"""向左移动所有行,返回新网格和总得分"""new_grid = []total_score = 0for row in self.grid:new_row, score = self._merge_line(row)new_grid.append(new_row)total_score += scorereturn new_grid, total_scoredef _move_right(self):"""向右移动:每行反转 -> 左移合并 -> 反转回来"""new_grid = []total_score = 0for row in self.grid:reversed_row = row[::-1]merged_row, score = self._merge_line(reversed_row)new_grid.append(merged_row[::-1])total_score += scorereturn new_grid, total_scoredef _move_up(self):"""向上移动:矩阵转置 -> 左移 -> 转置回来"""# 转置transposed = [[self.grid[r][c] for r in range(GRID_SIZE)] for c in range(GRID_SIZE)]new_trans, score = self._move_left() # 在转置矩阵上执行左移# 转置回来new_grid = [[new_trans[r][c] for r in range(GRID_SIZE)] for c in range(GRID_SIZE)]return new_grid, scoredef _move_down(self):"""向下移动:转置 -> 右移 -> 转置回来"""transposed = [[self.grid[r][c] for r in range(GRID_SIZE)] for c in range(GRID_SIZE)]new_trans, score = self._move_right()new_grid = [[new_trans[r][c] for r in range(GRID_SIZE)] for c in range(GRID_SIZE)]return new_grid, scoredef move(self, direction):"""执行移动操作direction: 'up', 'down', 'left', 'right'返回是否移动成功(网格发生变化)"""if self.game_over:return False# 保存当前状态,用于比较是否发生变化old_grid = [row[:] for row in self.grid]old_score = self.score# 根据方向调用相应移动方法if direction == 'left':new_grid, score_gain = self._move_left()elif direction == 'right':new_grid, score_gain = self._move_right()elif direction == 'up':new_grid, score_gain = self._move_up()elif direction == 'down':new_grid, score_gain = self._move_down()else:return False# 检查网格是否发生变化if new_grid == old_grid:return False# 更新网格和分数self.grid = new_gridself.score += score_gainself.update_highscore()# 移动成功后添加随机新数字self.add_random_tile()# 检查游戏是否结束if self.is_game_over():self.game_over = Truereturn Truedef draw_tile(screen, value, x, y):"""绘制单个格子"""# 选择颜色,如果值超过2048则使用2048颜色color = TILE_COLORS.get(value, TILE_COLORS[2048])rect = pygame.Rect(x, y, CELL_SIZE, CELL_SIZE)pygame.draw.rect(screen, color, rect, border_radius=8)pygame.draw.rect(screen, (187, 173, 160), rect, 2, border_radius=8) # 边框# 绘制数字if value != 0:# 根据数字大小选择字体和颜色if value < 8:text_color = DARK_TEXTelse:text_color = LIGHT_TEXT# 数字太大时缩小字体if value >= 1000:font = pygame.font.SysFont("arial", 24, bold=True)elif value >= 100:font = pygame.font.SysFont("arial", 28, bold=True)else:font = FONT_MEDIUMtext = font.render(str(value), True, text_color)text_rect = text.get_rect(center=(x + CELL_SIZE // 2, y + CELL_SIZE // 2))screen.blit(text, text_rect)def draw_game(screen, game):"""绘制整个游戏界面"""screen.fill(BG_COLOR)# 绘制标题title = FONT_LARGE.render("2048", True, DARK_TEXT)screen.blit(title, (GRID_LEFT, 20))# 绘制分数面板score_rect = pygame.Rect(WIDTH - 140, 20, 120, 50)pygame.draw.rect(screen, (187, 173, 160), score_rect, border_radius=6)score_text = FONT_SMALL.render("SCORE", True, LIGHT_TEXT)score_value = FONT_MEDIUM.render(str(game.score), True, LIGHT_TEXT)screen.blit(score_text, (WIDTH - 130, 25))screen.blit(score_value, (WIDTH - 125, 45))# 绘制最高分面板high_rect = pygame.Rect(WIDTH - 140, 80, 120, 45)pygame.draw.rect(screen, (187, 173, 160), high_rect, border_radius=6)high_text = FONT_SMALL.render("BEST", True, LIGHT_TEXT)high_value = FONT_MEDIUM.render(str(game.highscore), True, LIGHT_TEXT)screen.blit(high_text, (WIDTH - 130, 85))screen.blit(high_value, (WIDTH - 125, 105))# 绘制游戏网格for r in range(GRID_SIZE):for c in range(GRID_SIZE):x = GRID_LEFT + c * (CELL_SIZE + MARGIN)y = GRID_TOP + r * (CELL_SIZE + MARGIN)draw_tile(screen, game.grid[r][c], x, y)# 游戏结束或胜利提示if game.game_over:# 半透明覆盖层overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)overlay.fill((0, 0, 0, 180))screen.blit(overlay, (0, 0))# 游戏结束文字game_over_text = FONT_LARGE.render("GAME OVER", True, (255, 255, 255))restart_text = FONT_SMALL.render("Press R to restart", True, (255, 255, 255))screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - 40))screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT // 2 + 20))else:# 检查是否胜利(达到2048)if game.get_max_tile() >= 2048:win_text = FONT_MEDIUM.render("You Win!", True, (255, 215, 0))screen.blit(win_text, (GRID_LEFT, GRID_TOP - 35))# 提示操作hint = FONT_SMALL.render("Use arrow keys / R to restart", True, (119, 110, 101))screen.blit(hint, (WIDTH // 2 - hint.get_width() // 2, HEIGHT - 30))def main():"""主函数:游戏循环"""screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption("2048")clock = pygame.time.Clock()game = Game2048()running = Truewhile running:for event in pygame.event.get():if event.type == pygame.QUIT:running = Falsepygame.quit()sys.exit()elif event.type == pygame.KEYDOWN:if event.key == pygame.K_r:game.reset()elif not game.game_over:moved = Falseif event.key == pygame.K_LEFT:moved = game.move('left')elif event.key == pygame.K_RIGHT:moved = game.move('right')elif event.key == pygame.K_UP:moved = game.move('up')elif event.key == pygame.K_DOWN:moved = game.move('down')# 移动后更新显示(自动重绘)draw_game(screen, game)pygame.display.flip()clock.tick(30)pygame.quit()if __name__ == "__main__":main()
完毕!!感谢您的收看
--------★★历史博文集合★★--------
