Python 贪吃蛇游戏
2026-01-28 20:27:56
发布于:浙江
以下内容为AI生成,作者转载
import warnings
warnings.filterwarnings("ignore",
message="pkg_resources is deprecated as an API")
import pygame
import random
import sys
import os
# 初始化pygame
pygame.init()
# 游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_SIZE = 20
FPS = 10
# 方向
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
# 颜色定义
BACKGROUND_COLOR = (15, 15, 30)
GRID_COLOR = (30, 30, 50)
SNAKE_HEAD_COLOR = (0, 200, 100)
SNAKE_BODY_COLOR = (0, 180, 80)
FOOD_COLOR = (220, 50, 50)
TEXT_COLOR = (255, 255, 255)
BUTTON_COLOR = (70, 130, 180)
BUTTON_HOVER_COLOR = (100, 160, 210)
GAME_OVER_BG = (0, 0, 0, 180) # 半透明黑色
# 尝试加载中文字体,如果失败则使用默认英文字体
def load_font():
# 常见的中文字体列表,按优先级尝试
chinese_fonts = [
"msyh.ttc", # 微软雅黑
"simhei.ttf", # 黑体
"simsun.ttc", # 宋体
"STKAITI.TTF", # 楷体
"FZSTK.TTF", # 方正舒体
"DENG.TTF", # 等线
]
# 在Windows字体目录中查找中文字体
if sys.platform == "win32":
windir = os.environ.get("WINDIR", "C:\\Windows")
font_dirs = [os.path.join(windir, "Fonts")]
elif sys.platform == "darwin": # macOS
font_dirs = ["/System/Library/Fonts", "/Library/Fonts"]
else: # Linux
font_dirs = ["/usr/share/fonts", "/usr/local/share/fonts", os.path.expanduser("~/.fonts")]
# 添加当前目录
font_dirs.append(".")
# 尝试加载中文字体
for font_dir in font_dirs:
for font_name in chinese_fonts:
font_path = os.path.join(font_dir, font_name)
if os.path.exists(font_path):
try:
# 测试是否能成功加载
test_font = pygame.font.Font(font_path, 20)
print(f"成功加载字体: {font_path}")
return font_path
except:
continue
print("未找到中文字体,使用默认英文字体")
return None # 返回None将使用pygame默认字体
# 加载字体
font_path = load_font()
if font_path:
try:
font_large = pygame.font.Font(font_path, 48)
font_medium = pygame.font.Font(font_path, 36)
font_small = pygame.font.Font(font_path, 24)
font_tiny = pygame.font.Font(font_path, 18)
chinese_supported = True
except:
# 如果加载失败,使用默认字体
font_large = pygame.font.SysFont(None, 48)
font_medium = pygame.font.SysFont(None, 36)
font_small = pygame.font.SysFont(None, 24)
font_tiny = pygame.font.SysFont(None, 18)
chinese_supported = False
else:
font_large = pygame.font.SysFont(None, 48)
font_medium = pygame.font.SysFont(None, 36)
font_small = pygame.font.SysFont(None, 24)
font_tiny = pygame.font.SysFont(None, 18)
chinese_supported = False
# 根据字体支持情况选择文本
if chinese_supported:
TITLE_TEXT = "贪吃蛇游戏"
SCORE_TEXT = "得分: "
HIGH_SCORE_TEXT = "最高分: "
LENGTH_TEXT = "长度: "
GAME_OVER_TEXT = "游戏结束!"
RESTART_TEXT = "重新开始"
EXIT_TEXT = "退出游戏"
PAUSE_TEXT = "游戏暂停"
CONTINUE_TEXT = "按空格键继续"
FULLSCREEN_TEXT = "F11: 全屏切换 (全屏时隐藏鼠标)"
INSTRUCTIONS = [
"使用方向键或WASD控制蛇的移动",
"按空格键暂停/继续游戏",
"按F11键切换全屏/窗口模式",
"全屏模式下鼠标光标会自动隐藏",
"吃到红色食物可以增加长度和得分",
"避免撞到墙壁或自己的身体"
]
else:
TITLE_TEXT = "Snake Game"
SCORE_TEXT = "Score: "
HIGH_SCORE_TEXT = "High Score: "
LENGTH_TEXT = "Length: "
GAME_OVER_TEXT = "Game Over!"
RESTART_TEXT = "Restart"
EXIT_TEXT = "Exit Game"
PAUSE_TEXT = "Game Paused"
CONTINUE_TEXT = "Press SPACE to continue"
FULLSCREEN_TEXT = "F11: Toggle Fullscreen (Mouse hidden in fullscreen)"
INSTRUCTIONS = [
"Use arrow keys or WASD to control the snake",
"Press SPACE to pause/resume the game",
"Press F11 to toggle fullscreen mode",
"Mouse cursor is hidden in fullscreen mode",
"Eat red food to grow longer and earn points",
"Avoid walls and your own body"
]
class Snake:
def __init__(self, grid_width, grid_height):
self.grid_width = grid_width
self.grid_height = grid_height
self.reset()
def reset(self):
self.length = 3
self.positions = [(self.grid_width // 2, self.grid_height // 2)]
self.direction = RIGHT
self.next_direction = RIGHT
self.grow_pending = 2 # 初始长度为3,所以需要再增长2次
self.score = 0
def get_head_position(self):
return self.positions[0]
def update(self):
# 更新方向
self.direction = self.next_direction
# 获取头部位置
head = self.get_head_position()
x, y = self.direction
new_x = (head[0] + x) % self.grid_width
new_y = (head[1] + y) % self.grid_height
new_head = (new_x, new_y)
# 检查是否撞到自己
if new_head in self.positions[1:]:
return False # 游戏结束
# 添加新头部
self.positions.insert(0, new_head)
# 如果需要增长,则保留尾部,否则移除尾部
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
def draw(self, surface, grid_size, offset_x=0, offset_y=0):
for i, p in enumerate(self.positions):
# 绘制蛇身
color = SNAKE_HEAD_COLOR if i == 0 else SNAKE_BODY_COLOR
rect = pygame.Rect(
offset_x + p[0] * grid_size,
offset_y + p[1] * grid_size,
grid_size,
grid_size
)
pygame.draw.rect(surface, color, rect)
pygame.draw.rect(surface, (color[0]//2, color[1]//2, color[2]//2), rect, 1)
# 绘制蛇头眼睛
if i == 0:
eye_size = grid_size // 5
# 根据方向确定眼睛位置
if self.direction == RIGHT:
eye1_pos = (offset_x + p[0] * grid_size + grid_size - eye_size*2, offset_y + p[1] * grid_size + eye_size*2)
eye2_pos = (offset_x + p[0] * grid_size + grid_size - eye_size*2, offset_y + p[1] * grid_size + grid_size - eye_size*3)
elif self.direction == LEFT:
eye1_pos = (offset_x + p[0] * grid_size + eye_size, offset_y + p[1] * grid_size + eye_size*2)
eye2_pos = (offset_x + p[0] * grid_size + eye_size, offset_y + p[1] * grid_size + grid_size - eye_size*3)
elif self.direction == UP:
eye1_pos = (offset_x + p[0] * grid_size + eye_size*2, offset_y + p[1] * grid_size + eye_size)
eye2_pos = (offset_x + p[0] * grid_size + grid_size - eye_size*3, offset_y + p[1] * grid_size + eye_size)
else: # DOWN
eye1_pos = (offset_x + p[0] * grid_size + eye_size*2, offset_y + p[1] * grid_size + grid_size - eye_size*2)
eye2_pos = (offset_x + p[0] * grid_size + grid_size - eye_size*3, offset_y + p[1] * grid_size + grid_size - eye_size*2)
pygame.draw.rect(surface, (255, 255, 255), (eye1_pos[0], eye1_pos[1], eye_size, eye_size))
pygame.draw.rect(surface, (255, 255, 255), (eye2_pos[0], eye2_pos[1], eye_size, eye_size))
class Food:
def __init__(self, grid_width, grid_height):
self.grid_width = grid_width
self.grid_height = grid_height
self.position = (0, 0)
self.randomize_position()
def randomize_position(self):
self.position = (random.randint(0, self.grid_width - 1), random.randint(0, self.grid_height - 1))
def draw(self, surface, grid_size, offset_x=0, offset_y=0):
rect = pygame.Rect(
offset_x + self.position[0] * grid_size,
offset_y + self.position[1] * grid_size,
grid_size,
grid_size
)
pygame.draw.rect(surface, FOOD_COLOR, rect)
pygame.draw.rect(surface, (FOOD_COLOR[0]//2, FOOD_COLOR[1]//2, FOOD_COLOR[2]//2), rect, 1)
# 绘制食物内部细节
inner_margin = grid_size // 4
inner_rect = pygame.Rect(
offset_x + self.position[0] * grid_size + inner_margin,
offset_y + self.position[1] * grid_size + inner_margin,
grid_size - inner_margin * 2,
grid_size - inner_margin * 2
)
pygame.draw.rect(surface, (255, 150, 150), inner_rect)
class Button:
def __init__(self, x, y, width, height, text, action=None):
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.action = action
self.hovered = False
def draw(self, surface):
color = BUTTON_HOVER_COLOR if self.hovered else BUTTON_COLOR
pygame.draw.rect(surface, color, self.rect, border_radius=10)
pygame.draw.rect(surface, (255, 255, 255), self.rect, 2, border_radius=10)
text_surf = font_small.render(self.text, True, TEXT_COLOR)
text_rect = text_surf.get_rect(center=self.rect.center)
surface.blit(text_surf, text_rect)
def check_hover(self, pos):
self.hovered = self.rect.collidepoint(pos)
return self.hovered
def handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if self.hovered and self.action:
return self.action()
return None
class Game:
def __init__(self):
self.fullscreen = False
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption(TITLE_TEXT)
self.clock = pygame.time.Clock()
# 初始化游戏区域
self.grid_size = GRID_SIZE
self.update_grid_dimensions()
self.snake = Snake(self.grid_width, self.grid_height)
self.food = Food(self.grid_width, self.grid_height)
self.high_score = 0
self.game_over = False
self.paused = False
# 创建按钮
button_width = 200
button_height = 50
self.restart_button = Button(
0, 0, button_width, button_height,
RESTART_TEXT, self.restart_game
)
self.exit_button = Button(
0, 0, button_width, button_height,
EXIT_TEXT, self.quit_game
)
self.buttons = [self.restart_button, self.exit_button]
# 确保食物不在蛇身上
while self.food.position in self.snake.positions:
self.food.randomize_position()
# 更新按钮位置
self.update_button_positions()
# 初始状态下显示鼠标
pygame.mouse.set_visible(True)
def update_grid_dimensions(self):
"""更新网格尺寸和位置"""
screen_rect = self.screen.get_rect()
self.grid_width = screen_rect.width // self.grid_size
self.grid_height = (screen_rect.height - 140) // self.grid_size # 为分数和说明留出更多空间
# 计算游戏区域位置
self.game_area_width = self.grid_width * self.grid_size
self.game_area_height = self.grid_height * self.grid_size
self.game_area_x = (screen_rect.width - self.game_area_width) // 2
self.game_area_y = (screen_rect.height - self.game_area_height) // 2 + 40 # 为标题留出空间
def toggle_fullscreen(self):
"""切换全屏模式"""
self.fullscreen = not self.fullscreen
# 记录当前游戏状态
current_score = self.snake.score
current_high_score = self.high_score
current_game_over = self.game_over
current_paused = self.paused
if self.fullscreen:
# 获取当前显示器的分辨率
info = pygame.display.Info()
screen_width = info.current_w
screen_height = info.current_h
self.screen = pygame.display.set_mode((screen_width, screen_height), pygame.FULLSCREEN)
# 全屏时隐藏鼠标
pygame.mouse.set_visible(False)
else:
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 窗口模式时显示鼠标
pygame.mouse.set_visible(True)
# 更新网格尺寸
self.update_grid_dimensions()
# 重新创建蛇和食物(但保持游戏状态)
old_positions = self.snake.positions
old_direction = self.snake.direction
old_next_direction = self.snake.next_direction
old_grow_pending = self.snake.grow_pending
self.snake = Snake(self.grid_width, self.grid_height)
self.food = Food(self.grid_width, self.grid_height)
# 恢复蛇的状态
self.snake.score = current_score
self.snake.positions = []
for pos in old_positions:
# 调整位置到新的网格尺寸内
new_x = min(pos[0], self.grid_width - 1)
new_y = min(pos[1], self.grid_height - 1)
self.snake.positions.append((new_x, new_y))
self.snake.direction = old_direction
self.snake.next_direction = old_next_direction
self.snake.grow_pending = old_grow_pending
# 恢复其他游戏状态
self.high_score = current_high_score
self.game_over = current_game_over
self.paused = current_paused
# 确保食物不在蛇身上
while self.food.position in self.snake.positions:
self.food.randomize_position()
# 更新按钮位置
self.update_button_positions()
# 立即重绘屏幕
self.draw()
pygame.display.flip()
def update_button_positions(self):
"""更新按钮位置"""
screen_rect = self.screen.get_rect()
button_width = 200
button_height = 50
button_x = screen_rect.width // 2 - button_width // 2
self.restart_button.rect = pygame.Rect(
button_x, screen_rect.height // 2 + 60,
button_width, button_height
)
self.exit_button.rect = pygame.Rect(
button_x, screen_rect.height // 2 + 130,
button_width, button_height
)
def restart_game(self):
"""重新开始游戏"""
self.snake.reset()
self.food.randomize_position()
self.game_over = False
self.paused = False
# 确保食物不在蛇身上
while self.food.position in self.snake.positions:
self.food.randomize_position()
return True
def quit_game(self):
"""退出游戏"""
pygame.quit()
sys.exit()
def handle_events(self):
"""处理游戏事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.quit_game()
if event.type == pygame.KEYDOWN:
# F11切换全屏
if event.key == pygame.K_F11:
self.toggle_fullscreen()
# ESC键也可以退出全屏
elif event.key == pygame.K_ESCAPE and self.fullscreen:
self.toggle_fullscreen()
if not self.game_over:
if event.key == pygame.K_SPACE:
self.paused = not self.paused
if not self.paused:
# 方向控制
if event.key in (pygame.K_UP, pygame.K_w) and self.snake.direction != DOWN:
self.snake.next_direction = UP
elif event.key in (pygame.K_DOWN, pygame.K_s) and self.snake.direction != UP:
self.snake.next_direction = DOWN
elif event.key in (pygame.K_LEFT, pygame.K_a) and self.snake.direction != RIGHT:
self.snake.next_direction = LEFT
elif event.key in (pygame.K_RIGHT, pygame.K_d) and self.snake.direction != LEFT:
self.snake.next_direction = RIGHT
else:
# 游戏结束后按空格重新开始
if event.key == pygame.K_SPACE:
self.restart_game()
# 处理按钮事件(只在窗口模式或游戏结束时有按钮)
if self.game_over:
# 在全屏模式下,如果鼠标隐藏,当用户移动鼠标时显示它
if self.fullscreen and event.type == pygame.MOUSEMOTION:
pygame.mouse.set_visible(True)
mouse_pos = pygame.mouse.get_pos()
for button in self.buttons:
button.check_hover(mouse_pos)
button.handle_event(event)
def update(self):
"""更新游戏状态"""
if self.game_over or self.paused:
return
# 更新蛇的位置
if not self.snake.update():
self.game_over = True
# 更新最高分
if self.snake.score > self.high_score:
self.high_score = self.snake.score
return
# 检查是否吃到食物
if self.snake.get_head_position() == self.food.position:
self.snake.grow()
self.food.randomize_position()
# 确保食物不在蛇身上
while self.food.position in self.snake.positions:
self.food.randomize_position()
def draw_grid(self):
"""绘制游戏区域的网格"""
# 绘制游戏区域内的网格线
for x in range(self.game_area_x, self.game_area_x + self.game_area_width + 1, self.grid_size):
pygame.draw.line(self.screen, GRID_COLOR, (x, self.game_area_y), (x, self.game_area_y + self.game_area_height))
for y in range(self.game_area_y, self.game_area_y + self.game_area_height + 1, self.grid_size):
pygame.draw.line(self.screen, GRID_COLOR, (self.game_area_x, y), (self.game_area_x + self.game_area_width, y))
def draw_score(self):
"""绘制分数和游戏信息"""
screen_rect = self.screen.get_rect()
score_text = font_medium.render(f"{SCORE_TEXT}{self.snake.score}", True, TEXT_COLOR)
high_score_text = font_medium.render(f"{HIGH_SCORE_TEXT}{self.high_score}", True, TEXT_COLOR)
self.screen.blit(score_text, (20, 20))
self.screen.blit(high_score_text, (20, 70))
# 显示当前长度
length_text = font_small.render(f"{LENGTH_TEXT}{len(self.snake.positions)}", True, TEXT_COLOR)
self.screen.blit(length_text, (20, 120))
# 显示全屏提示
fullscreen_text = font_tiny.render(FULLSCREEN_TEXT, True, (200, 200, 255))
self.screen.blit(fullscreen_text, (20, screen_rect.height - 60))
# 显示游戏标题
title_text = font_large.render(TITLE_TEXT, True, (100, 200, 255))
title_x = screen_rect.width // 2 - title_text.get_width() // 2
self.screen.blit(title_text, (title_x, 10))
def draw_instructions(self):
"""绘制游戏说明"""
screen_rect = self.screen.get_rect()
for i, line in enumerate(INSTRUCTIONS):
instruction_text = font_tiny.render(line, True, (200, 200, 255))
self.screen.blit(instruction_text, (screen_rect.width - instruction_text.get_width() - 20, 20 + i * 30))
def draw_game_area(self):
"""绘制游戏区域"""
# 绘制游戏区域背景
game_area_rect = pygame.Rect(
self.game_area_x,
self.game_area_y,
self.game_area_width,
self.game_area_height
)
pygame.draw.rect(self.screen, BACKGROUND_COLOR, game_area_rect)
# 绘制游戏区域边框
pygame.draw.rect(self.screen, (100, 100, 150), game_area_rect, 2)
# 绘制网格
self.draw_grid()
# 绘制蛇和食物
self.snake.draw(self.screen, self.grid_size, self.game_area_x, self.game_area_y)
self.food.draw(self.screen, self.grid_size, self.game_area_x, self.game_area_y)
def draw_game_over(self):
"""绘制游戏结束界面"""
screen_rect = self.screen.get_rect()
# 半透明覆盖层
overlay = pygame.Surface((screen_rect.width, screen_rect.height), pygame.SRCALPHA)
overlay.fill(GAME_OVER_BG)
self.screen.blit(overlay, (0, 0))
# 游戏结束文本
game_over_text = font_large.render(GAME_OVER_TEXT, True, (255, 100, 100))
self.screen.blit(game_over_text, (screen_rect.width // 2 - game_over_text.get_width() // 2, screen_rect.height // 4))
# 最终得分
score_text = font_medium.render(f"{SCORE_TEXT}{self.snake.score}", True, TEXT_COLOR)
self.screen.blit(score_text, (screen_rect.width // 2 - score_text.get_width() // 2, screen_rect.height // 4 + 80))
# 绘制按钮
for button in self.buttons:
button.draw(self.screen)
# 在全屏模式下显示鼠标(如果用户需要点击按钮)
if self.fullscreen:
pygame.mouse.set_visible(True)
def draw_pause_screen(self):
"""绘制暂停界面"""
screen_rect = self.screen.get_rect()
# 半透明覆盖层
overlay = pygame.Surface((screen_rect.width, screen_rect.height), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 128))
self.screen.blit(overlay, (0, 0))
# 暂停文本
pause_text = font_large.render(PAUSE_TEXT, True, TEXT_COLOR)
self.screen.blit(pause_text, (screen_rect.width // 2 - pause_text.get_width() // 2, screen_rect.height // 3))
# 继续提示
continue_text = font_medium.render(CONTINUE_TEXT, True, TEXT_COLOR)
self.screen.blit(continue_text, (screen_rect.width // 2 - continue_text.get_width() // 2, screen_rect.height // 2))
def draw(self):
"""绘制整个游戏画面"""
self.screen.fill(BACKGROUND_COLOR)
# 绘制游戏区域
self.draw_game_area()
# 绘制分数和说明
self.draw_score()
self.draw_instructions()
# 绘制游戏结束画面
if self.game_over:
self.draw_game_over()
# 绘制暂停画面
if self.paused and not self.game_over:
self.draw_pause_screen()
pygame.display.flip()
def run(self):
"""运行游戏主循环"""
while True:
self.handle_events()
self.update()
self.draw()
self.clock.tick(FPS)
if __name__ == "__main__":
game = Game()
game.run()
运行这个程序,你需要安装Python
并安装PyGame:
pip install pygame
(安装指南)
这里空空如也
















有帮助,赞一个