Python版贪吃蛇(最后附上完整代码并有详细注释):从零开始用Pygame实现经典游戏
一、前言:童年经典游戏重生
贪吃蛇作为一款经典游戏,承载着无数人的童年回忆。今天我们将用Python+pygame从零开始实现这个经典游戏!通过本教程,你不仅能掌握游戏开发的基本流程,还能学习到实用的编程技巧。先来看看最终效果:
二、开发准备
环境要求
-
Python 3.9
-
Pygame==2.6.1库(
pip install pygame==
2.6.1)
三、核心代码解析
3.1 游戏初始化
- # 初始化Pygame引擎
- pygame.init()
-
- # 创建游戏窗口
- screen = pygame.display.set_mode((800, 600))
- pygame.display.set_caption("贪吃蛇大作战")
3.2 游戏常量配置
- WINDOW_WIDTH = 800 # 窗口宽度
- WINDOW_HEIGHT = 600 # 窗口高度
- CELL_SIZE = 20 # 蛇身和食物的单位尺寸
- COLORS = { # 颜色字典
- "BLACK": (0,0,0),
- "WHITE": (255,255,255),
- "RED": (255,0,0),
- # ...其他颜色
- }
3.3 蛇的移动控制
- # 方向向量控制:通过元组存储方向
- current_dir = (1, 0) # 初始向右
-
- # 键盘事件处理(防止180度转向)
- if event.key == pygame.K_UP:
- new_dir = (0, -1)
- # 判断新方向是否合法(非相反方向)
- if (current_dir[0] + new_dir[0] != 0) or ...:
- current_dir = new_dir
四、关键技术实现
4.1 蛇身绘制技巧
- # 渐变颜色区分头身
- for i, (x, y) in enumerate(snake):
- color = COLORS["SNAKE_HEAD"] if i==0 else COLORS["SNAKE_BODY"]
- # 圆角矩形提升美观度
- pygame.draw.rect(screen, color, (x,y,CELL_SIZE-1,CELL_SIZE-1), border_radius=4)
4.2 智能食物生成
- def generate_food():
- while True:
- # 随机生成坐标
- x = random.randint(0, (WIDTH-CELL_SIZE)//CELL_SIZE) * CELL_SIZE
- y = ...
- # 确保不在蛇身上
- if (x,y) not in snake:
- return (x,y)
4.3 碰撞检测系统
- # 边界检测
- new_head[0] < 0 or new_head[0] >= WIDTH...
-
- # 自碰检测
- new_head in snake
-
- # 食物碰撞检测
- new_head == food_pos
五、特色功能实现
5.1 速度切换系统
- # 按住方向键加速
- accelerate = any(keys[k] for k in (pygame.K_UP, ...))
- # 动态调整帧率
- Clock().tick(ACCELERATE_FPS if accelerate else BASE_FPS)
5.2 高分记录系统
- def load_highscore():
- try:
- with open('highscore.txt') as f:
- return int(f.read())
- except:
- return 0
-
- def save_highscore():
- with open('highscore.txt', 'w') as f:
- f.write(str(high_score))
六、游戏逻辑流程图
- graph TD
- A[游戏初始化] --> B[主循环]
- B --> C{事件处理}
- C -->|按键| D[更新方向]
- C -->|退出| E[结束游戏]
- B --> F[移动蛇头]
- F --> G{碰撞检测}
- G -->|碰墙/自身| H[游戏结束]
- G -->|吃到食物| I[增长蛇身]
- G -->|正常移动| J[更新位置]
- B --> K[重绘画面]
扩展方向
-
增加不同难度级别
-
添加多种特殊食物(加速、减速等)
-
实现多人对战模式
-
加入背景音乐和音效
七、总结
通过本教程,我们完整实现了:
-
游戏窗口创建与绘制
-
蛇的移动与控制逻辑
-
智能食物生成系统
-
完善的碰撞检测
-
高分记录功能
-
动态速度调节
八、完整代码
- # -*- coding: utf-8 -*-
- import pygame
- import random
- import sys
-
- # 初始化pygame(必须的步骤,用于初始化所有pygame模块)
- pygame.init()
-
- # === 游戏常量配置 ===
- WINDOW_WIDTH = 800 # 游戏窗口宽度(单位:像素)
- WINDOW_HEIGHT = 600 # 游戏窗口高度(单位:像素)
- CELL_SIZE = 20 # 网格单元格大小(单位:像素)
- BASE_FPS = 5 # 基础游戏帧率(控制蛇的正常移动速度)
- ACCELERATE_FPS = 14 # 加速时的游戏帧率
-
- # 颜色定义(RGB格式)
- COLORS = {
- "BLACK": (0, 0, 0),
- "WHITE": (255, 255, 255),
- "RED": (255, 0, 0),
- "GREEN": (0, 255, 0),
- "BLUE": (0, 100, 200),
- "GRID": (40, 40, 40), # 网格线颜色
- "SNAKE_HEAD": (0, 255, 0), # 蛇头颜色
- "SNAKE_BODY": (0, 200, 0) # 蛇身颜色
- }
-
- # === 游戏状态初始化 ===
- snake = [] # 用列表存储蛇身体的坐标(每个元素是一个元组)
- current_dir = (1, 0) # 当前移动方向(使用向量表示,初始向右)
- food_pos = (0, 0) # 食物位置坐标
- is_playing = True # 游戏是否进行中的状态
- score = 0 # 当前游戏分数
- high_score = 0 # 历史最高分记录
-
- # 初始化游戏窗口
- screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
- pygame.display.set_caption("贪吃蛇大作战") # 窗口标题
-
-
- def draw_grid():
- """绘制网格线背景,帮助玩家更好地观察位置"""
- # 绘制垂直网格线
- for x in range(0, WINDOW_WIDTH, CELL_SIZE):
- pygame.draw.line(screen, COLORS["GRID"], (x, 0), (x, WINDOW_HEIGHT))
- # 绘制水平网格线
- for y in range(0, WINDOW_HEIGHT, CELL_SIZE):
- pygame.draw.line(screen, COLORS["GRID"], (0, y), (WINDOW_WIDTH, y))
-
-
- def generate_food():
- """生成食物坐标,确保不在蛇身体上"""
- while True:
- # 计算网格坐标(确保在窗口范围内)
- x = random.randint(0, (WINDOW_WIDTH - CELL_SIZE) // CELL_SIZE) * CELL_SIZE
- y = random.randint(0, (WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE) * CELL_SIZE
- # 检查生成位置是否与蛇身体重叠
- if (x, y) not in snake:
- return (x, y)
-
-
- def reset_game():
- """重置游戏所有状态到初始值"""
- global snake, current_dir, food_pos, is_playing, score
- snake = [(WINDOW_WIDTH // 2, WINDOW_HEIGHT // 2)] # 蛇初始位置在窗口中心
- current_dir = (1, 0) # 初始方向向右
- food_pos = generate_food() # 生成第一个食物
- is_playing = True # 游戏状态设置为进行中
- score = 0 # 重置当前分数
-
-
- def show_text(content, size, color, position):
- """在指定位置显示文字的工具函数"""
- font = pygame.font.SysFont('simhei', size) # 使用黑体字
- text_surface = font.render(content, True, color)
- screen.blit(text_surface, position)
-
-
- def load_highscore():
- """从文件读取历史最高分"""
- try:
- with open('highscore.txt', 'r') as f:
- return int(f.read())
- except FileNotFoundError:
- return 0 # 文件不存在时返回0分
-
-
- def save_highscore():
- """保存最高分到文件"""
- with open('highscore.txt', 'w') as f:
- f.write(str(high_score))
-
-
- # 初始化游戏
- high_score = load_highscore()
- reset_game()
-
- # === 主游戏循环 ===
- while True:
- # 处理事件队列(包括按键、窗口关闭等)
- for event in pygame.event.get():
- if event.type == pygame.QUIT: # 点击窗口关闭按钮
- pygame.quit()
- sys.exit()
- elif event.type == pygame.KEYDOWN:
- if event.key == pygame.K_q: # Q键退出
- pygame.quit()
- sys.exit()
- if event.key == pygame.K_r and not is_playing: # R键重启游戏
- reset_game()
- # 方向键控制(已解决反向问题)
- if is_playing:
- new_dir = current_dir # 默认保持当前方向
- if event.key == pygame.K_UP:
- new_dir = (0, -1)
- elif event.key == pygame.K_DOWN:
- new_dir = (0, 1)
- elif event.key == pygame.K_LEFT:
- new_dir = (-1, 0)
- elif event.key == pygame.K_RIGHT:
- new_dir = (1, 0)
- # 禁止直接反向(只有当新方向不相反时更新)
- if (current_dir[0] + new_dir[0] != 0) or (current_dir[1] + new_dir[1] != 0):
- current_dir = new_dir
-
- # 获取当前按键状态实现加速功能
- keys = pygame.key.get_pressed()
- # 检查是否有方向键被按住(使用位运算优化判断)
- accelerate = any(keys[k] for k in (pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT))
-
- # 游戏进行中的逻辑处理
- if is_playing:
- # 计算新蛇头位置
- head_x, head_y = snake[0]
- dir_x, dir_y = current_dir
- new_head = (head_x + dir_x * CELL_SIZE, head_y + dir_y * CELL_SIZE)
-
- # 碰撞检测(边界和自身)
- if (new_head in snake or
- new_head[0] < 0 or
- new_head[0] >= WINDOW_WIDTH or
- new_head[1] < 0 or
- new_head[1] >= WINDOW_HEIGHT):
- is_playing = False
- # 更新最高分记录
- if score > high_score:
- high_score = score
- save_highscore()
-
- # 更新蛇的位置
- snake.insert(0, new_head)
- if new_head == food_pos: # 吃到食物
- score += 10
- food_pos = generate_food()
- else: # 没吃到食物时移除尾部
- snake.pop()
-
- # === 绘制游戏画面 ===
- screen.fill(COLORS["BLACK"]) # 填充背景色
- draw_grid() # 绘制网格线
-
- # 绘制蛇的身体(使用渐变颜色)
- for i, (x, y) in enumerate(snake):
- # 根据部位设置颜色(头部更亮)
- color = COLORS["SNAKE_HEAD"] if i == 0 else COLORS["SNAKE_BODY"]
- # 绘制带圆角的蛇身
- pygame.draw.rect(screen, color, (x, y, CELL_SIZE - 1, CELL_SIZE - 1), border_radius=4)
-
- # 绘制食物(使用圆形)
- center = (food_pos[0] + CELL_SIZE // 2, food_pos[1] + CELL_SIZE // 2)
- pygame.draw.circle(screen, COLORS["RED"], center, CELL_SIZE // 2 - 2)
-
- # 显示分数信息
- show_text(f"分数: {score} 最高分: {high_score}", 24, COLORS["WHITE"], (10, 10))
-
- # 游戏结束显示提示
- if not is_playing:
- text_width = 400 # 根据文字长度估算居中位置
- show_text("游戏结束!按 R 重新开始", 48, COLORS["WHITE"],
- (WINDOW_WIDTH // 2 - text_width // 2, WINDOW_HEIGHT // 2 - 30))
-
- # 更新画面并控制游戏速度
- pygame.display.update()
- # 根据加速状态动态调整帧率
- pygame.time.Clock().tick(ACCELERATE_FPS if accelerate else BASE_FPS)
评论记录:
回复评论: