文章目录
前言
下面是最终运行的效果图,这个用简单一个三个类实现这个小游戏,用到了Python中的pygamed的库。环境配置完后,可以直接复制完整代码进行,就可以运行得到结果。代码中有详细注释,后续也有对每个类的实现进行补充说明。
一、Python实现经典贪吃蛇游戏:从基础到进阶
贪吃蛇是一款经典的休闲游戏,其简单的规则和富有挑战性的玩法使其长盛不衰。本文将基于Pygame库实现一个功能完善的贪吃蛇游戏,包含分数统计、关卡系统和速度递增等进阶功能,适合Python初学者学习游戏开发入门。

二、开发准备
环境配置
本项目需要使用Pygame库进行游戏开发,首先确保已安装相关依赖:
pip install pygame
游戏核心功能规划
我们将实现的贪吃蛇游戏包含以下功能:
- 蛇的移动、转向和身体增长机制
- 随机生成食物及碰撞检测
- 分数计算和关卡进阶系统
- 速度随关卡提升的难度调节
- 游戏结束和重新开始功能
- 中文显示支持
游戏界面
最后实现效果:


三、核心代码解析
完整代码
这部分是完整代码,安装好对应库就可以直接右键运行起来。
# 导入必要的库
import pygame # 游戏引擎库
import sys # 系统操作库
import random # 随机数生成库
# 初始化pygame引擎
pygame.init()
# 颜色常量定义 (R, G, B)
WHITE = (255, 255, 255) # 白色
RED = (255, 0, 0) # 红色(食物)
GREEN = (0, 255, 0) # 绿色(蛇身)
BLUE = (0, 0, 255) # 蓝色(未使用)
BLACK = (0, 0, 0) # 黑色(背景)
YELLOW = (255, 255, 0) # 黄色(UI文字)
# 游戏常量定义
SCREEN_WIDTH = 800 # 屏幕宽度(像素)
SCREEN_HEIGHT = 600 # 屏幕高度(像素)
GRID_SIZE = 20 # 网格单元大小(像素)
GRID_WIDTH = SCREEN_WIDTH // GRID_SIZE # 网格宽度(单元格数)
GRID_HEIGHT = SCREEN_HEIGHT // GRID_SIZE # 网格高度(单元格数)
INITIAL_SPEED = 5 # 初始移动速度(帧/秒)
SPEED_INCREMENT = 0.5 # 每关速度增量
MAX_LEVEL = 10 # 最大关卡数
TARGET_SCORE = 100 # 通关所需分数
# 方向常量(x, y偏移量)
UP = (0, -1) # 向上移动
DOWN = (0, 1) # 向下移动
LEFT = (-1, 0) # 向左移动
RIGHT = (1, 0) # 向右移动
class Snake:
"""蛇类,管理蛇的行为和状态"""
def __init__(self):
# 初始化蛇的状态
self.reset()
def reset(self):
"""重置蛇到初始状态"""
# 蛇身初始位置在屏幕中央(单个方块)
self.body = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
# 随机选择初始方向
self.direction = random.choice([UP, DOWN, LEFT, RIGHT])
# 标记是否需要增长身体
self.grow_pending = False
def move(self):
"""移动蛇的身体"""
# 获取当前蛇头位置
head_x, head_y = self.body[0]
# 获取移动方向偏移量
dx, dy = self.direction
# 计算新蛇头位置
new_head = (head_x + dx, head_y + dy)
# 碰撞检测:撞墙或撞到自己
if (new_head in self.body or
new_head[0] < 0 or new_head[0] >= GRID_WIDTH or
new_head[1] < 0 or new_head[1] >= GRID_HEIGHT):
return False # 碰撞发生,游戏结束
# 在头部添加新位置
self.body.insert(0, new_head)
if not self.grow_pending:
# 不需要增长时,移除尾部保持长度不变
self.body.pop()
else:
# 重置增长标记
self.grow_pending = False
return True # 移动成功
def grow(self):
"""标记蛇需要增长身体"""
self.grow_pending = True
def draw(self, surface):
"""在指定表面绘制蛇"""
# 遍历蛇的每个身体部分
for i, segment in enumerate(self.body):
# 将网格坐标转换为像素坐标
x, y = segment
# 创建矩形对象(位置和大小)
rect = pygame.Rect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
# 绘制蛇身(绿色填充)
pygame.draw.rect(surface, GREEN, rect)
# 绘制蛇身边框(黑色)
pygame.draw.rect(surface, BLACK, rect, 1)
class Food:
"""食物类,管理食物的位置和生成"""
def __init__(self, snake_body):
# 初始位置
self.position = None
# 在蛇身之外生成食物
self.spawn(snake_body)
def spawn(self, snake_body):
"""在蛇身之外随机生成新食物"""
while True:
# 随机生成网格坐标
x = random.randint(0, GRID_WIDTH - 1)
y = random.randint(0, GRID_HEIGHT - 1)
# 确保食物不会生成在蛇身上
if (x, y) not in snake_body:
self.position = (x, y) # 设置食物位置
break
def draw(self, surface):
"""在指定表面绘制食物"""
# 将网格坐标转换为像素坐标
x, y = self.position
# 创建矩形对象
rect = pygame.Rect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
# 绘制食物(红色填充)
pygame.draw.rect(surface, RED, rect)
# 绘制食物边框(黑色)
pygame.draw.rect(surface, BLACK, rect, 1)
class Game:
"""游戏主类,管理游戏状态和逻辑"""
def __init__(self):
# 创建游戏窗口
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption('贪吃蛇')
# 创建时钟对象,用于控制游戏速度
self.clock = pygame.time.Clock()
# 查找支持中文的字体(黑体/微软雅黑/宋体)
chinese_font = pygame.font.match_font("simhei, microsoftyahei, simsun")
# 设置游戏字体
self.font = pygame.font.Font(chinese_font, 36)
# 重置游戏状态
self.reset()
def reset(self):
"""重置游戏到初始状态"""
# 创建新的蛇实例
self.snake = Snake()
# 创建新的食物实例(确保不在蛇身上)
self.food = Food(self.snake.body)
# 重置分数
self.score = 0
# 重置关卡
self.level = 1
# 重置速度
self.speed = INITIAL_SPEED
# 重置游戏结束标志
self.game_over = False
# 重置关卡完成标志
self.level_complete = False
def run(self):
"""运行游戏主循环"""
while True:
# 处理用户输入事件
self.handle_events()
# 如果游戏未结束且未完成当前关卡,更新游戏状态
if not self.game_over and not self.level_complete:
self.update()
# 绘制游戏界面
self.draw()
# 根据当前速度控制帧率
self.clock.tick(self.speed)
def handle_events(self):
"""处理所有用户输入事件"""
for event in pygame.event.get():
# 处理退出事件
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 处理按键事件
elif event.type == pygame.KEYDOWN:
if self.game_over:
# 游戏结束后按R重新开始
if event.key == pygame.K_r:
self.reset()
elif self.level_complete:
# 关卡完成后按N进入下一关
if event.key == pygame.K_n:
self.next_level()
else:
# 游戏进行中处理方向控制
self.handle_direction(event.key)
def handle_direction(self, key):
"""处理方向键输入,控制蛇的移动方向"""
# 上方向键:不能反向移动(不能从向下改为向上)
if key == pygame.K_UP and self.snake.direction != DOWN:
self.snake.direction = UP
# 下方向键:不能反向移动
elif key == pygame.K_DOWN and self.snake.direction != UP:
self.snake.direction = DOWN
# 左方向键:不能反向移动
elif key == pygame.K_LEFT and self.snake.direction != RIGHT:
self.snake.direction = LEFT
# 右方向键:不能反向移动
elif key == pygame.K_RIGHT and self.snake.direction != LEFT:
self.snake.direction = RIGHT
def update(self):
"""更新游戏状态(每帧执行)"""
# 移动蛇的身体
if not self.snake.move():
# 移动失败(碰撞发生)
self.game_over = True
return
# 检查是否吃到食物
if self.snake.body[0] == self.food.position:
# 蛇需要增长身体
self.snake.grow()
# 增加分数
self.score += 1
# 重新生成食物
self.food.spawn(self.snake.body)
# 检查是否达到通关分数
if self.score >= TARGET_SCORE:
self.level_complete = True
def draw(self):
"""绘制游戏界面"""
# 用黑色填充背景
self.screen.fill(BLACK)
# 绘制网格线(暗灰色)
for x in range(0, SCREEN_WIDTH, GRID_SIZE):
pygame.draw.line(self.screen, (40, 40, 40), (x, 0), (x, SCREEN_HEIGHT))
for y in range(0, SCREEN_HEIGHT, GRID_SIZE):
pygame.draw.line(self.screen, (40, 40, 40), (0, y), (SCREEN_WIDTH, y))
# 绘制蛇和食物
self.snake.draw(self.screen)
self.food.draw(self.screen)
# 绘制分数和关卡信息
score_text = self.font.render(f"分数: {self.score}/{TARGET_SCORE} 等级: {self.level}", True, WHITE)
speed_text = self.font.render(f"速度: {self.speed:.1f}", True, WHITE)
# 将文本绘制到屏幕指定位置
self.screen.blit(score_text, (10, 10))
self.screen.blit(speed_text, (10, 50))
# 如果游戏结束,绘制结束画面
if self.game_over:
self.draw_game_over()
# 如果关卡完成,绘制完成画面
if self.level_complete:
self.draw_level_complete()
# 更新屏幕显示
pygame.display.flip()
def draw_game_over(self):
"""绘制游戏结束画面"""
# 创建半透明黑色覆盖层
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180)) # 半透明黑色
self.screen.blit(overlay, (0, 0))
# 渲染游戏结束文本
game_over_text = self.font.render("游戏结束!", True, WHITE)
score_text = self.font.render(f"最终分数: {self.score}", True, WHITE)
restart_text = self.font.render("按 R 重新开始", True, YELLOW)
# 将文本居中绘制到屏幕
self.screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, SCREEN_HEIGHT // 2 - 60))
self.screen.blit(score_text, (SCREEN_WIDTH // 2 - score_text.get_width() // 2, SCREEN_HEIGHT // 2))
self.screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, SCREEN_HEIGHT // 2 + 60))
def draw_level_complete(self):
"""绘制关卡完成画面"""
# 创建半透明黑色覆盖层
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180)) # 半透明黑色
self.screen.blit(overlay, (0, 0))
# 渲染关卡完成文本
congrats_text = self.font.render("恭喜通关!", True, YELLOW)
level_text = self.font.render(f"你完成了第 {self.level} 关!", True, WHITE)
next_text = self.font.render("按 N 进入下一关", True, YELLOW)
# 将文本居中绘制到屏幕
self.screen.blit(congrats_text, (SCREEN_WIDTH // 2 - congrats_text.get_width() // 2, SCREEN_HEIGHT // 2 - 60))
self.screen.blit(level_text, (SCREEN_WIDTH // 2 - level_text.get_width() // 2, SCREEN_HEIGHT // 2))
self.screen.blit(next_text, (SCREEN_WIDTH // 2 - next_text.get_width() // 2, SCREEN_HEIGHT // 2 + 60))
def next_level(self):
"""进入下一关卡"""
if self.level < MAX_LEVEL:
# 增加关卡数
self.level += 1
# 增加游戏速度
self.speed += SPEED_INCREMENT
# 重置游戏状态(保留分数)
self.reset()
else:
# 达到最大关卡,游戏结束
self.game_over = True
# 主程序入口
if __name__ == "__main__":
# 创建游戏实例
game = Game()
# 开始游戏主循环
game.run()
1. 初始化与常量定义
首先导入必要的库并进行初始化,同时定义游戏中使用的常量:
import pygame
import sys
import random
# 初始化pygame引擎
pygame.init()
# 颜色常量定义 (R, G, B)
WHITE = (255, 255, 255)
RED = (255, 0, 0) # 食物颜色
GREEN = (0, 255, 0) # 蛇身颜色
BLACK = (0, 0, 0) # 背景颜色
YELLOW = (255, 255, 0) # 提示文字颜色
# 游戏常量定义
SCREEN_WIDTH = 800 # 屏幕宽度
SCREEN_HEIGHT = 600 # 屏幕高度
GRID_SIZE = 20 # 网格单元大小
GRID_WIDTH = SCREEN_WIDTH // GRID_SIZE # 网格宽度(单元格数)
GRID_HEIGHT = SCREEN_HEIGHT // GRID_SIZE # 网格高度(单元格数)
INITIAL_SPEED = 5 # 初始速度
SPEED_INCREMENT = 0.5 # 每关速度增量
MAX_LEVEL = 10 # 最大关卡数
TARGET_SCORE = 100 # 通关分数
# 方向常量(x, y偏移量)
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
2. 蛇类实现(Snake)
蛇是游戏的核心元素,我们需要实现其移动、增长和碰撞检测等功能:
class Snake:
"""蛇类,管理蛇的行为和状态"""
def __init__(self):
self.reset() # 初始化蛇的状态
def reset(self):
"""重置蛇到初始状态"""
# 初始位置在屏幕中央
self.body = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
# 随机初始方向
self.direction = random.choice([UP, DOWN, LEFT, RIGHT])
# 身体增长标记
self.grow_pending = False
def move(self):
"""移动蛇的身体,返回是否移动成功"""
head_x, head_y = self.body[0]
dx, dy = self.direction
new_head = (head_x + dx, head_y + dy)
# 碰撞检测:撞墙或撞到自己
if (new_head in self.body or
new_head[0] < 0 or new_head[0] >= GRID_WIDTH or
new_head[1] < 0 or new_head[1] >= GRID_HEIGHT):
return False # 碰撞发生
# 添加新头部
self.body.insert(0, new_head)
# 处理身体增长
if not self.grow_pending:
self.body.pop() # 不增长时移除尾部
else:
self.grow_pending = False # 重置增长标记
return True
def grow(self):
"""标记蛇需要增长身体"""
self.grow_pending = True
def draw(self, surface):
"""绘制蛇到屏幕"""
for segment in self.body:
x, y = segment
rect = pygame.Rect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, GREEN, rect)
pygame.draw.rect(surface, BLACK, rect, 1) # 边框
蛇的移动逻辑采用了"添加新头部并移除尾部"的方式实现,当吃到食物时则保留尾部实现增长效果。
3. 食物类实现(Food)
食物类负责在蛇身之外随机生成食物:
class Food:
"""食物类,管理食物的位置和生成"""
def __init__(self, snake_body):
self.position = None
self.spawn(snake_body) # 初始生成
def spawn(self, snake_body):
"""在蛇身之外生成新食物"""
while True:
# 随机生成位置
x = random.randint(0, GRID_WIDTH - 1)
y = random.randint(0, GRID_HEIGHT - 1)
# 确保不在蛇身上
if (x, y) not in snake_body:
self.position = (x, y)
break
def draw(self, surface):
"""绘制食物到屏幕"""
x, y = self.position
rect = pygame.Rect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, RED, rect)
pygame.draw.rect(surface, BLACK, rect, 1) # 边框
食物生成时会进行碰撞检测,确保不会出现在蛇的身体上,保证游戏的合理性。
4. 游戏主类(Game)
游戏主类负责整合所有元素,处理事件、更新状态和绘制画面:
class Game:
"""游戏主类,管理游戏状态和逻辑"""
def __init__(self):
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('贪吃蛇')
self.clock = pygame.time.Clock()
# 配置中文字体
chinese_font = pygame.font.match_font("simhei, microsoftyahei, simsun")
self.font = pygame.font.Font(chinese_font, 36)
self.reset()
def reset(self):
"""重置游戏状态"""
self.snake = Snake()
self.food = Food(self.snake.body)
self.score = 0
self.level = 1
self.speed = INITIAL_SPEED
self.game_over = False
self.level_complete = False
游戏主循环
游戏主循环是处理用户输入、更新游戏状态和绘制画面的核心:
def run(self):
"""运行游戏主循环"""
while True:
self.handle_events() # 处理输入
# 更新游戏状态
if not self.game_over and not self.level_complete:
self.update()
self.draw() # 绘制画面
self.clock.tick(self.speed) # 控制帧率
事件处理
处理用户输入,包括方向控制、重新开始和关卡切换:
def handle_events(self):
"""处理用户输入事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if self.game_over:
if event.key == pygame.K_r: # 重新开始
self.reset()
elif self.level_complete:
if event.key == pygame.K_n: # 下一关
self.next_level()
else:
self.handle_direction(event.key) # 方向控制
def handle_direction(self, key):
"""处理方向键输入"""
if key == pygame.K_UP and self.snake.direction != DOWN:
self.snake.direction = UP
elif key == pygame.K_DOWN and self.snake.direction != UP:
self.snake.direction = DOWN
elif key == pygame.K_LEFT and self.snake.direction != RIGHT:
self.snake.direction = LEFT
elif key == pygame.K_RIGHT and self.snake.direction != LEFT:
self.snake.direction = RIGHT
方向控制中加入了防反向逻辑,避免蛇直接反向移动导致立即碰撞。
游戏状态更新
def update(self):
"""更新游戏状态"""
# 移动蛇
if not self.snake.move():
self.game_over = True
return
# 检测是否吃到食物
if self.snake.body[0] == self.food.position:
self.snake.grow() # 蛇增长
self.score += 1 # 加分
self.food.spawn(self.snake.body) # 生成新食物
# 检测是否通关
if self.score >= TARGET_SCORE:
self.level_complete = True
画面绘制
def draw(self):
"""绘制游戏画面"""
self.screen.fill(BLACK) # 填充背景
# 绘制网格
for x in range(0, SCREEN_WIDTH, GRID_SIZE):
pygame.draw.line(self.screen, (40, 40, 40), (x, 0), (x, SCREEN_HEIGHT))
for y in range(0, SCREEN_HEIGHT, GRID_SIZE):
pygame.draw.line(self.screen, (40, 40, 40), (0, y), (SCREEN_WIDTH, y))
# 绘制蛇和食物
self.snake.draw(self.screen)
self.food.draw(self.screen)
# 绘制分数和关卡信息
score_text = self.font.render(f"分数: {self.score}/{TARGET_SCORE} 等级: {self.level}", True, WHITE)
speed_text = self.font.render(f"速度: {self.speed:.1f}", True, WHITE)
self.screen.blit(score_text, (10, 10))
self.screen.blit(speed_text, (10, 50))
# 绘制游戏状态画面
if self.game_over:
self.draw_game_over()
if self.level_complete:
self.draw_level_complete()
pygame.display.flip() # 更新显示
5. 关卡系统与游戏结束
实现关卡进阶和游戏结束逻辑:
def next_level(self):
"""进入下一关卡"""
if self.level < MAX_LEVEL:
self.level += 1
self.speed += SPEED_INCREMENT # 提升速度
self.reset() # 重置游戏但保留关卡信息
else:
self.game_over = True # 达到最大关卡
def draw_game_over(self):
"""绘制游戏结束画面"""
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180)) # 半透明覆盖层
self.screen.blit(overlay, (0, 0))
# 绘制文字
game_over_text = self.font.render("游戏结束!", True, WHITE)
score_text = self.font.render(f"最终分数: {self.score}", True, WHITE)
restart_text = self.font.render("按 R 重新开始", True, YELLOW)
# 居中显示
self.screen.blit(game_over_text, (SCREEN_WIDTH//2 - game_over_text.get_width()//2, SCREEN_HEIGHT//2 - 60))
self.screen.blit(score_text, (SCREEN_WIDTH//2 - score_text.get_width()//2, SCREEN_HEIGHT//2))
self.screen.blit(restart_text, (SCREEN_WIDTH//2 - restart_text.get_width()//2, SCREEN_HEIGHT//2 + 60))
四、游戏运行与扩展
启动游戏
在代码末尾添加主程序入口:
if __name__ == "__main__":
game = Game()
game.run()
运行程序即可开始游戏,使用方向键控制蛇的移动,吃到红色食物得分,撞到墙壁或自身则游戏结束。
功能扩展建议
- 增加特殊食物:随机生成具有限时效果的特殊食物(如加速、减速、额外分数等)
- 音效系统:添加移动、吃食物、游戏结束等音效
- 排行榜:记录玩家的最高分数
- 自定义难度:允许玩家选择初始速度和关卡设置
- 皮肤系统:提供不同的蛇和食物外观选择
五、总结
本文实现了一个功能完整的贪吃蛇游戏,通过面向对象的方式将游戏元素模块化,使代码结构清晰、易于维护和扩展。核心难点在于蛇的移动逻辑和碰撞检测,通过合理的数据结构(列表存储蛇身)和算法(头部添加与尾部移除)实现了流畅的游戏体验。
这个项目非常适合Python初学者练习面向对象编程和游戏开发基础,通过不断扩展功能可以深入理解游戏开发的核心原理。
&spm=1001.2101.3001.5002&articleId=152126147&d=1&t=3&u=3bb1e2bf2cf84f10b30e59e93eb6ba39)
4676

被折叠的 条评论
为什么被折叠?



