🎮 游戏简介
贪吃蛇是一款经典的游戏,玩家通过键盘方向键控制一条蛇在屏幕上移动,吃掉随机出现的食物来增长身体,同时要避免撞到墙壁或自己的身体。这个项目非常适合 Python 初学者学习游戏开发基础。xu0713#True
🛠️ 环境准备
确保你的 Python 环境已安装以下库:
bash
pip install pygame
如果没有安装 pip,请先安装 Python 包管理工具。
📦 完整代码实现
python
import pygame
import random
import sys
# 初始化 Pygame
pygame.init()
# 游戏常量
WIDTH, HEIGHT = 600, 600
GRID_SIZE = 20
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE
FPS = 10
# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 120, 255)
GRAY = (40, 40, 40)
# 方向常量
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
class Snake:
def __init__(self):
self.reset()
def reset(self):
"""重置蛇的状态"""
self.length = 3
self.positions = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
self.direction = RIGHT
self.score = 0
self.grow_pending = 2 # 初始长度为3,需要再生长2节
def get_head_position(self):
"""获取蛇头位置"""
return self.positions[0]
def turn(self, point):
"""改变蛇的移动方向"""
# 防止直接反向移动(例如:向右移动时不能直接向左转)
if self.length > 1 and (point[0] * -1, point[1] * -1) == self.direction:
return
self.direction = point
def move(self):
"""移动蛇"""
head = self.get_head_position()
x, y = self.direction
new_x = (head[0] + x) % GRID_WIDTH
new_y = (head[1] + y) % GRID_HEIGHT
new_position = (new_x, new_y)
# 检查是否撞到自己
if new_position in self.positions[1:]:
return False # 游戏结束
self.positions.insert(0, new_position)
# 处理生长逻辑
if self.grow_pending > 0:
self.grow_pending -= 1
else:
self.positions.pop()
return True # 游戏继续
def grow(self):
"""蛇吃到食物后生长"""
self.grow_pending += 1
self.score += 10
self.length += 1
def draw(self, surface):
"""绘制蛇"""
for i, p in enumerate(self.positions):
# 蛇头用不同颜色
color = BLUE if i == 0 else GREEN
# 绘制蛇身方块
rect = pygame.Rect(
p[0] * GRID_SIZE,
p[1] * GRID_SIZE,
GRID_SIZE,
GRID_SIZE
)
pygame.draw.rect(surface, color, rect)
pygame.draw.rect(surface, BLACK, rect, 1) # 黑色边框
# 为蛇头添加眼睛
if i == 0:
eye_size = GRID_SIZE // 5
# 根据方向确定眼睛位置
if self.direction == RIGHT:
eye1 = (rect.right - eye_size*2, rect.top + eye_size*2)
eye2 = (rect.right - eye_size*2, rect.bottom - eye_size*3)
elif self.direction == LEFT:
eye1 = (rect.left + eye_size, rect.top + eye_size*2)
eye2 = (rect.left + eye_size, rect.bottom - eye_size*3)
elif self.direction == UP:
eye1 = (rect.left + eye_size*2, rect.top + eye_size)
eye2 = (rect.right - eye_size*3, rect.top + eye_size)
else: # DOWN
eye1 = (rect.left + eye_size*2, rect.bottom - eye_size*2)
eye2 = (rect.right - eye_size*3, rect.bottom - eye_size*2)
pygame.draw.circle(surface, WHITE, eye1, eye_size)
pygame.draw.circle(surface, WHITE, eye2, eye_size)
pygame.draw.circle(surface, BLACK, eye1, eye_size//2)
pygame.draw.circle(surface, BLACK, eye2, eye_size//2)
class Food:
def __init__(self):
self.position = (0, 0)
self.randomize_position()
def randomize_position(self):
"""随机生成食物位置"""
self.position = (
random.randint(0, GRID_WIDTH - 1),
random.randint(0, GRID_HEIGHT - 1)
)
def draw(self, surface):
"""绘制食物"""
rect = pygame.Rect(
self.position[0] * GRID_SIZE,
self.position[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE
)
pygame.draw.rect(surface, RED, rect)
pygame.draw.rect(surface, BLACK, rect, 1) # 黑色边框
# 添加食物内部的细节
inner_rect = pygame.Rect(
self.position[0] * GRID_SIZE + GRID_SIZE//4,
self.position[1] * GRID_SIZE + GRID_SIZE//4,
GRID_SIZE//2, GRID_SIZE//2
)
pygame.draw.rect(surface, (255, 200, 200), inner_rect)
def draw_grid(surface):
"""绘制游戏网格"""
for y in range(0, HEIGHT, GRID_SIZE):
for x in range(0, WIDTH, GRID_SIZE):
rect = pygame.Rect(x, y, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, GRAY, rect, 1)
def draw_score(surface, score, high_score):
"""绘制分数显示"""
font = pygame.font.SysFont('arial', 25)
score_text = font.render(f'得分: {score}', True, WHITE)
high_score_text = font.render(f'最高分: {high_score}', True, WHITE)
surface.blit(score_text, (10, 10))
surface.blit(high_score_text, (WIDTH - high_score_text.get_width() - 10, 10))
def draw_game_over(surface, score):
"""绘制游戏结束画面"""
font_large = pygame.font.SysFont('arial', 50)
font_small = pygame.font.SysFont('arial', 30)
game_over_text = font_large.render('游戏结束!', True, RED)
score_text = font_small.render(f'最终得分: {score}', True, WHITE)
restart_text = font_small.render('按 R 键重新开始', True, GREEN)
quit_text = font_small.render('按 Q 键退出游戏', True, WHITE)
# 居中显示
surface.blit(game_over_text, (WIDTH//2 - game_over_text.get_width()//2, HEIGHT//2 - 80))
surface.blit(score_text, (WIDTH//2 - score_text.get_width()//2, HEIGHT//2 - 20))
surface.blit(restart_text, (WIDTH//2 - restart_text.get_width()//2, HEIGHT//2 + 20))
surface.blit(quit_text, (WIDTH//2 - quit_text.get_width()//2, HEIGHT//2 + 60))
def main():
# 初始化游戏窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Python 贪吃蛇小游戏')
clock = pygame.time.Clock()
# 创建游戏对象
snake = Snake()
food = Food()
# 游戏状态
game_over = False
high_score = 0
# 主游戏循环
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if game_over:
if event.key == pygame.K_r: # 重新开始
snake.reset()
food.randomize_position()
game_over = False
elif event.key == pygame.K_q: # 退出游戏
pygame.quit()
sys.exit()
else:
# 控制蛇的移动方向
if event.key == pygame.K_UP:
snake.turn(UP)
elif event.key == pygame.K_DOWN:
snake.turn(DOWN)
elif event.key == pygame.K_LEFT:
snake.turn(LEFT)
elif event.key == pygame.K_RIGHT:
snake.turn(RIGHT)
if not game_over:
# 移动蛇
if not snake.move():
game_over = True
high_score = max(high_score, snake.score)
# 检查是否吃到食物
if snake.get_head_position() == food.position:
snake.grow()
food.randomize_position()
# 确保食物不会出现在蛇身上
while food.position in snake.positions:
food.randomize_position()
# 绘制游戏画面
screen.fill(BLACK)
draw_grid(screen)
if not game_over:
snake.draw(screen)
food.draw(screen)
draw_score(screen, snake.score, high_score)
else:
draw_game_over(screen, snake.score)
pygame.display.update()
clock.tick(FPS)
if __name__ == "__main__":
main()
🎯 游戏功能说明
1. 核心功能
- 蛇的移动:使用方向键(↑↓←→)控制蛇的移动方向
- 食物系统:随机生成红色食物,蛇吃到后身体变长,得分增加
- 碰撞检测 :
- 撞到自己身体 → 游戏结束
- 穿过边界 → 从对面重新出现(可修改为撞墙结束)
- 分数系统:每吃一个食物得10分,显示当前得分和最高分
2. 视觉设计
- 蛇头为蓝色,蛇身为绿色
- 蛇头有方向性的眼睛
- 食物有内外两层颜色
- 网格背景便于定位
- 游戏结束画面显示最终得分和操作提示
3. 游戏控制
- 游戏中:方向键控制移动
- 游戏结束后 :
- R 键:重新开始游戏
- Q 键:退出游戏
🔧 自定义修改建议
1. 调整游戏难度
python
# 提高游戏速度(增加FPS)
FPS = 15
# 减小网格尺寸(增加格子数量)
GRID_SIZE = 15
GRID_WIDTH = WIDTH // GRID_SIZE # 40个格子
GRID_HEIGHT = HEIGHT // GRID_SIZE # 40个格子
2. 修改为撞墙结束模式
python
# 在 Snake.move() 方法中修改边界检测
def move(self):
head = self.get_head_position()
x, y = self.direction
new_x = head[0] + x
new_y = head[1] + y
# 检查是否撞墙
if new_x < 0 or new_x >= GRID_WIDTH or new_y < 0 or new_y >= GRID_HEIGHT:
return False # 游戏结束
# ... 其余代码不变
3. 添加音效(需要音效文件)
python
# 初始化音效
pygame.mixer.init()
eat_sound = pygame.mixer.Sound("eat.wav")
game_over_sound = pygame.mixer.Sound("game_over.wav")
# 在吃到食物时播放音效
if snake.get_head_position() == food.position:
snake.grow()
eat_sound.play() # 播放吃食物音效
food.randomize_position()
🚀 运行与调试
-
保存代码 :将完整代码保存为
snake_game.py -
运行游戏:
bash
python snake_game.py
- 常见问题解决 :
-
问题 :
ModuleNotFoundError: No module named 'pygame' -
解决 :运行
pip install pygame -
问题:游戏窗口无法关闭
-
解决:按 Q 键或点击窗口关闭按钮
-
问题:游戏速度太快/太慢
-
解决 :调整代码中的
FPS值
-
📚 学习要点
通过这个项目,你可以学习到:
- Pygame 基础:窗口创建、事件处理、图形绘制
- 面向对象编程:Snake 和 Food 类的设计
- 游戏循环:主循环、状态更新、画面渲染
- 碰撞检测:位置比较算法
- 状态管理:游戏进行中、结束等状态切换
💡 扩展挑战
尝试为游戏添加以下功能:
- 多种食物类型:不同颜色的食物给予不同分数
- 障碍物系统:随机生成的障碍物,碰到即结束
- 关卡系统:随着分数增加,速度逐渐加快
- 保存最高分:将最高分保存到文件
- 开始菜单:添加游戏开始菜单和难度选择
🎉 总结
这个贪吃蛇游戏项目涵盖了 Python 游戏开发的核心概念,代码结构清晰,注释详细,非常适合学习和修改。你可以根据自己的想法添加更多功能,创造属于自己的独特版本!
祝你编程愉快! 🐍✨