""" 经典贪吃蛇游戏 使用方向键控制蛇的移动,吃到食物后蛇会变长 撞墙或撞到自己则游戏结束 """ import pygame import random import sys from enum import Enum from typing import Tuple, List class Direction(Enum): """方向枚举""" UP = (0, -1) DOWN = (0, 1) LEFT = (-1, 0) RIGHT = (1, 0) class SnakeGame: """贪吃蛇游戏类""" def __init__(self, width: int = 800, height: int = 600, cell_size: int = 20): """ 初始化游戏 Args: width: 游戏窗口宽度 height: 游戏窗口高度 cell_size: 每个格子的大小 """ self.width = width self.height = height self.cell_size = cell_size # 计算网格数量 self.grid_width = width // cell_size self.grid_height = height // cell_size # 初始化 Pygame pygame.init() self.screen = pygame.display.set_mode((width, height)) pygame.display.set_caption("🐍 经典贪吃蛇") self.clock = pygame.time.Clock() # 字体 self.font_large = pygame.font.Font(None, 74) self.font_medium = pygame.font.Font(None, 48) self.font_small = pygame.font.Font(None, 36) # 颜色定义 self.colors = { 'background': (15, 23, 42), # 深蓝色背景 'snake_head': (34, 197, 94), # 绿色蛇头 'snake_body': (22, 163, 74), # 深绿色蛇身 'food': (239, 68, 68), # 红色食物 'grid': (30, 41, 59), # 网格线 'text': (255, 255, 255), # 白色文字 'score_bg': (51, 65, 85) # 分数背景 } # 游戏状态 self.reset_game() def reset_game(self): """重置游戏状态""" # 蛇的初始位置(中心) start_x = self.grid_width // 2 start_y = self.grid_height // 2 self.snake: List[Tuple[int, int]] = [ (start_x, start_y), (start_x - 1, start_y), (start_x - 2, start_y) ] # 初始方向(向右) self.direction = Direction.RIGHT self.next_direction = Direction.RIGHT # 生成第一个食物 self.food = self._generate_food() # 游戏状态 self.score = 0 self.game_over = False self.paused = False self.speed = 10 # 初始速度(FPS) def _generate_food(self) -> Tuple[int, int]: """ 生成食物位置 Returns: 食物的坐标 (x, y) """ while True: food_pos = ( random.randint(0, self.grid_width - 1), random.randint(0, self.grid_height - 1) ) # 确保食物不会生成在蛇身上 if food_pos not in self.snake: return food_pos def _handle_events(self): """处理事件""" for event in pygame.event.get(): if event.type == pygame.QUIT: return False if event.type == pygame.KEYDOWN: if self.game_over: if event.key == pygame.K_SPACE or event.key == pygame.K_RETURN: self.reset_game() elif event.key == pygame.K_ESCAPE: return False else: # 暂停功能 if event.key == pygame.K_p: self.paused = not self.paused # 方向控制 if event.key in [pygame.K_UP, pygame.K_w]: if self.direction != Direction.DOWN: self.next_direction = Direction.UP elif event.key in [pygame.K_DOWN, pygame.K_s]: if self.direction != Direction.UP: self.next_direction = Direction.DOWN elif event.key in [pygame.K_LEFT, pygame.K_a]: if self.direction != Direction.RIGHT: self.next_direction = Direction.LEFT elif event.key in [pygame.K_RIGHT, pygame.K_d]: if self.direction != Direction.LEFT: self.next_direction = Direction.RIGHT elif event.key == pygame.K_ESCAPE: return False return True def _update(self): """更新游戏状态""" if self.game_over or self.paused: return # 更新方向 self.direction = self.next_direction # 计算新的头部位置 head_x, head_y = self.snake[0] dx, dy = self.direction.value new_head = (head_x + dx, head_y + dy) # 检查碰撞 if self._check_collision(new_head): self.game_over = True return # 移动蛇 self.snake.insert(0, new_head) # 检查是否吃到食物 if new_head == self.food: self.score += 10 self.food = self._generate_food() # 每吃 5 个食物加速一次 if self.score % 50 == 0: self.speed = min(self.speed + 2, 25) # 最大速度 25 else: # 没吃到食物,移除尾部 self.snake.pop() def _check_collision(self, position: Tuple[int, int]) -> bool: """ 检查碰撞 Args: position: 要检查的位置 Returns: 是否发生碰撞 """ x, y = position # 撞墙 if x < 0 or x >= self.grid_width or y < 0 or y >= self.grid_height: return True # 撞到自己 if position in self.snake: return True return False def _draw_grid(self): """绘制网格背景""" for x in range(0, self.width, self.cell_size): pygame.draw.line(self.screen, self.colors['grid'], (x, 0), (x, self.height)) for y in range(0, self.height, self.cell_size): pygame.draw.line(self.screen, self.colors['grid'], (0, y), (self.width, y)) def _draw_snake(self): """绘制蛇""" for i, (x, y) in enumerate(self.snake): rect = pygame.Rect( x * self.cell_size, y * self.cell_size, self.cell_size - 2, self.cell_size - 2 ) # 蛇头颜色不同 color = self.colors['snake_head'] if i == 0 else self.colors['snake_body'] pygame.draw.rect(self.screen, color, rect, border_radius=5) # 画蛇眼睛 if i == 0: eye_size = 4 if self.direction == Direction.UP: eye1_pos = (x * self.cell_size + 5, y * self.cell_size + 5) eye2_pos = (x * self.cell_size + self.cell_size - 9, y * self.cell_size + 5) elif self.direction == Direction.DOWN: eye1_pos = (x * self.cell_size + 5, y * self.cell_size + self.cell_size - 9) eye2_pos = (x * self.cell_size + self.cell_size - 9, y * self.cell_size + self.cell_size - 9) elif self.direction == Direction.LEFT: eye1_pos = (x * self.cell_size + 5, y * self.cell_size + 5) eye2_pos = (x * self.cell_size + 5, y * self.cell_size + self.cell_size - 9) else: # RIGHT eye1_pos = (x * self.cell_size + self.cell_size - 9, y * self.cell_size + 5) eye2_pos = (x * self.cell_size + self.cell_size - 9, y * self.cell_size + self.cell_size - 9) pygame.draw.circle(self.screen, (255, 255, 255), eye1_pos, eye_size) pygame.draw.circle(self.screen, (255, 255, 255), eye2_pos, eye_size) def _draw_food(self): """绘制食物""" x, y = self.food center_x = x * self.cell_size + self.cell_size // 2 center_y = y * self.cell_size + self.cell_size // 2 # 画圆形食物 pygame.draw.circle(self.screen, self.colors['food'], (center_x, center_y), self.cell_size // 2 - 2) # 画高光 highlight_pos = (center_x - 3, center_y - 3) pygame.draw.circle(self.screen, (255, 100, 100), highlight_pos, 3) def _draw_score(self): """绘制分数""" # 分数背景 score_rect = pygame.Rect(10, 10, 200, 50) pygame.draw.rect(self.screen, self.colors['score_bg'], score_rect, border_radius=10) # 分数文字 score_text = self.font_small.render(f"Score: {self.score}", True, self.colors['text']) self.screen.blit(score_text, (20, 25)) # 速度显示 speed_text = self.font_small.render(f"Speed: {self.speed}", True, self.colors['text']) self.screen.blit(speed_text, (120, 25)) def _draw_game_over(self): """绘制游戏结束画面""" # 半透明遮罩 overlay = pygame.Surface((self.width, self.height)) overlay.set_alpha(128) overlay.fill((0, 0, 0)) self.screen.blit(overlay, (0, 0)) # 游戏结束文字 game_over_text = self.font_large.render("GAME OVER", True, self.colors['food']) text_rect = game_over_text.get_rect(center=(self.width // 2, self.height // 2 - 50)) self.screen.blit(game_over_text, text_rect) # 分数 score_text = self.font_medium.render(f"Final Score: {self.score}", True, self.colors['text']) score_rect = score_text.get_rect(center=(self.width // 2, self.height // 2 + 20)) self.screen.blit(score_text, score_rect) # 提示文字 hint_text = self.font_small.render("Press SPACE to Restart", True, self.colors['text']) hint_rect = hint_text.get_rect(center=(self.width // 2, self.height // 2 + 80)) self.screen.blit(hint_text, hint_rect) hint_text2 = self.font_small.render("Press ESC to Quit", True, self.colors['text']) hint_rect2 = hint_text2.get_rect(center=(self.width // 2, self.height // 2 + 120)) self.screen.blit(hint_text2, hint_rect2) def _draw_paused(self): """绘制暂停画面""" # 半透明遮罩 overlay = pygame.Surface((self.width, self.height)) overlay.set_alpha(128) overlay.fill((0, 0, 0)) self.screen.blit(overlay, (0, 0)) # 暂停文字 pause_text = self.font_large.render("PAUSED", True, self.colors['text']) text_rect = pause_text.get_rect(center=(self.width // 2, self.height // 2)) self.screen.blit(pause_text, text_rect) hint_text = self.font_small.render("Press P to Resume", True, self.colors['text']) hint_rect = hint_text.get_rect(center=(self.width // 2, self.height // 2 + 60)) self.screen.blit(hint_text, hint_rect) def draw(self): """绘制游戏画面""" # 清空屏幕 self.screen.fill(self.colors['background']) # 绘制网格 self._draw_grid() # 绘制食物 self._draw_food() # 绘制蛇 self._draw_snake() # 绘制分数 self._draw_score() # 游戏结束画面 if self.game_over: self._draw_game_over() # 暂停画面 if self.paused: self._draw_paused() # 更新显示 pygame.display.flip() def run(self): """运行游戏主循环""" running = True while running: # 处理事件 running = self._handle_events() # 更新游戏状态 self._update() # 绘制画面 self.draw() # 控制帧率 self.clock.tick(self.speed) pygame.quit() sys.exit() def main(): """主函数""" print("=" * 60) print("🐍 经典贪吃蛇游戏") print("=" * 60) print("\n游戏说明:") print(" - 使用方向键 ↑↓←→ 或 WASD 控制蛇的移动") print(" - 吃到红色食物可以得分并变长") print(" - 撞墙或撞到自己则游戏结束") print(" - 按 P 键暂停游戏") print(" - 按 ESC 键退出游戏") print(" - 按空格键重新开始") print("\n每吃 5 个食物,速度会加快哦!") print("=" * 60) print("\n正在启动游戏...") game = SnakeGame() game.run() if __name__ == "__main__": main()