跳转至

实战项目5:贪吃蛇游戏

项目概述

实现经典的贪吃蛇游戏,玩家控制蛇移动吃食物,蛇会逐渐变长。这是一个非常好的游戏开发入门项目,可以帮助你学习游戏编程的基本概念。

学习目标

  • 掌握pygame游戏开发框架
  • 学习游戏循环和事件处理
  • 理解碰撞检测算法
  • 掌握游戏状态管理
  • 学习面向对象游戏编程

功能需求

基本功能

  1. 蛇的移动:使用方向键控制蛇的移动方向
  2. 食物生成:随机生成食物
  3. 吃食物:蛇吃到食物后变长,得分增加
  4. 碰撞检测:检测蛇是否撞墙或撞到自己
  5. 游戏结束:碰撞后游戏结束,显示最终分数

进阶功能

  1. 难度选择:简单、普通、困难三种难度
  2. 最高分记录:保存和显示最高分
  3. 暂停功能:按空格键暂停游戏
  4. 音效:添加游戏音效
  5. 动画效果:平滑的移动和转向动画

高级功能

  1. 多种模式:经典模式、无尽模式、关卡模式
  2. 障碍物:添加障碍物增加难度
  3. 特殊食物:不同食物有不同效果
  4. 多人游戏:支持双人游戏
  5. 排行榜:在线排行榜

实现方案

基础实现

import pygame
import random
import sys

# 初始化pygame
pygame.init()

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# 游戏配置
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_SIZE = 20
GRID_WIDTH = SCREEN_WIDTH // GRID_SIZE
GRID_HEIGHT = SCREEN_HEIGHT // GRID_SIZE
FPS = 10

class SnakeGame:
    """贪吃蛇游戏类"""

    def __init__(self):
        """初始化游戏"""
        self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption("贪吃蛇游戏")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.Font(None, 36)

        self.reset_game()

    def reset_game(self):
        """重置游戏"""
        # 蛇的初始位置
        self.snake = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
        self.direction = (0, -1)  # 向上移动

        # 生成食物
        self.food = self.generate_food()

        # 分数
        self.score = 0
        self.high_score = self.load_high_score()

        # 游戏状态
        self.game_over = False
        self.paused = False

    def generate_food(self):
        """生成食物"""
        while True:
            food = (random.randint(0, GRID_WIDTH - 1),
                   random.randint(0, GRID_HEIGHT - 1))
            if food not in self.snake:
                return food

    def load_high_score(self):
        """加载最高分"""
        try:
            with open('high_score.txt', 'r') as f:
                return int(f.read())
        except:
            return 0

    def save_high_score(self):
        """保存最高分"""
        if self.score > self.high_score:
            self.high_score = self.score
            with open('high_score.txt', 'w') as f:
                f.write(str(self.high_score))

    def handle_events(self):
        """处理事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    return False

                if event.key == pygame.K_SPACE:
                    if self.game_over:
                        self.reset_game()
                    else:
                        self.paused = not self.paused

                if not self.paused and not self.game_over:
                    if event.key == pygame.K_UP and self.direction != (0, 1):
                        self.direction = (0, -1)
                    elif event.key == pygame.K_DOWN and self.direction != (0, -1):
                        self.direction = (0, 1)
                    elif event.key == pygame.K_LEFT and self.direction != (1, 0):
                        self.direction = (-1, 0)
                    elif event.key == pygame.K_RIGHT and self.direction != (-1, 0):
                        self.direction = (1, 0)

        return True

    def update(self):
        """更新游戏状态"""
        if self.game_over or self.paused:
            return

        # 计算新的头部位置
        head = self.snake[0]
        new_head = (head[0] + self.direction[0],
                   head[1] + self.direction[1])

        # 检查碰撞
        if (new_head[0] < 0 or new_head[0] >= GRID_WIDTH or
            new_head[1] < 0 or new_head[1] >= GRID_HEIGHT or
            new_head in self.snake):
            self.game_over = True
            self.save_high_score()
            return

        # 移动蛇
        self.snake.insert(0, new_head)

        # 检查是否吃到食物
        if new_head == self.food:
            self.score += 10
            self.food = self.generate_food()
        else:
            self.snake.pop()

    def draw(self):
        """绘制游戏画面"""
        self.screen.fill(BLACK)

        # 绘制蛇
        for segment in self.snake:
            rect = pygame.Rect(segment[0] * GRID_SIZE,
                             segment[1] * GRID_SIZE,
                             GRID_SIZE, GRID_SIZE)
            pygame.draw.rect(self.screen, GREEN, rect)
            pygame.draw.rect(self.screen, WHITE, rect, 1)  # 边框

        # 绘制食物
        food_rect = pygame.Rect(self.food[0] * GRID_SIZE,
                               self.food[1] * GRID_SIZE,
                               GRID_SIZE, GRID_SIZE)
        pygame.draw.rect(self.screen, RED, food_rect)

        # 绘制分数
        score_text = self.font.render(f"分数: {self.score}", True, WHITE)
        high_score_text = self.font.render(f"最高分: {self.high_score}", True, WHITE)
        self.screen.blit(score_text, (10, 10))
        self.screen.blit(high_score_text, (10, 50))

        # 游戏结束提示
        if self.game_over:
            game_over_text = self.font.render("游戏结束!按空格键重新开始", True, WHITE)
            text_rect = game_over_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
            self.screen.blit(game_over_text, text_rect)

        # 暂停提示
        if self.paused and not self.game_over:
            pause_text = self.font.render("游戏暂停 - 按空格键继续", True, WHITE)
            text_rect = pause_text.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))
            self.screen.blit(pause_text, text_rect)

        pygame.display.flip()

    def run(self):
        """运行游戏"""
        running = True
        while running:
            running = self.handle_events()
            self.update()
            self.draw()
            self.clock.tick(FPS)

        pygame.quit()
        sys.exit()

# 运行游戏
if __name__ == "__main__":
    game = SnakeGame()
    game.run()

面向对象版本

class Snake:
    """蛇类"""

    def __init__(self, start_pos):
        """初始化蛇"""
        self.body = [start_pos]
        self.direction = (0, -1)
        self.grow_pending = 0

    def change_direction(self, new_direction):
        """改变方向"""
        # 不能反向移动
        if (new_direction[0] * -1, new_direction[1] * -1) != self.direction:
            self.direction = new_direction

    def move(self):
        """移动蛇"""
        head = self.body[0]
        new_head = (head[0] + self.direction[0],
                   head[1] + self.direction[1])

        self.body.insert(0, new_head)

        if self.grow_pending > 0:
            self.grow_pending -= 1
        else:
            self.body.pop()

    def check_collision(self, width, height):
        """检查碰撞"""
        head = self.body[0]

        # 检查墙壁碰撞
        if (head[0] < 0 or head[0] >= width or
            head[1] < 0 or head[1] >= height):
            return True

        # 检查自身碰撞
        if head in self.body[1:]:
            return True

        return False

    def eat(self):
        """吃食物"""
        self.grow_pending += 1

class Food:
    """食物类"""

    def __init__(self, width, height):
        """初始化食物"""
        self.width = width
        self.height = height
        self.position = (0, 0)
        self.respawn([])

    def respawn(self, snake_body):
        """重新生成食物"""
        while True:
            self.position = (random.randint(0, self.width - 1),
                           random.randint(0, self.height - 1))
            if self.position not in snake_body:
                break

扩展功能

1. 添加难度选择

DIFFICULTY_LEVELS = {
    '简单': {'speed': 8, 'points': 5},
    '普通': {'speed': 10, 'points': 10},
    '困难': {'speed': 15, 'points': 20}
}

def select_difficulty():
    """选择难度"""
    print("选择难度:")
    for i, level in enumerate(DIFFICULTY_LEVELS.keys(), 1):
        print(f"{i}. {level}")

    choice = input("请选择(1-3):")
    levels = list(DIFFICULTY_LEVELS.keys())
    if choice.isdigit() and 1 <= int(choice) <= len(levels):
        return DIFFICULTY_LEVELS[levels[int(choice) - 1]]
    return DIFFICULTY_LEVELS['普通']

2. 添加特殊食物

SPECIAL_FOODS = {
    'normal': {'color': RED, 'points': 10, 'effect': None},
    'speed': {'color': BLUE, 'points': 20, 'effect': 'speed_up'},
    'slow': {'color': (255, 255, 0), 'points': 15, 'effect': 'slow_down'},
    'shrink': {'color': (255, 0, 255), 'points': 30, 'effect': 'shrink'}
}

def generate_special_food():
    """生成特殊食物"""
    rand = random.random()
    if rand < 0.7:
        return 'normal'
    elif rand < 0.85:
        return 'speed'
    elif rand < 0.95:
        return 'slow'
    else:
        return 'shrink'

3. 添加音效

import pygame.mixer

def init_sounds():
    """初始化音效"""
    pygame.mixer.init()

    sounds = {}
    try:
        sounds['eat'] = pygame.mixer.Sound('eat.wav')
        sounds['crash'] = pygame.mixer.Sound('crash.wav')
        sounds['game_over'] = pygame.mixer.Sound('game_over.wav')
    except:
        print("音效文件未找到,将使用静音模式")
        sounds = None

    return sounds

def play_sound(sounds, sound_name):
    """播放音效"""
    if sounds and sound_name in sounds:
        sounds[sound_name].play()

测试方法

def test_snake_movement():
    """测试蛇的移动"""
    snake = Snake((10, 10))
    assert len(snake.body) == 1
    assert snake.direction == (0, -1)

    snake.move()
    assert len(snake.body) == 1
    assert snake.body[0] == (10, 9)

    snake.change_direction((1, 0))
    snake.move()
    assert snake.body[0] == (11, 9)

    snake.eat()
    snake.move()
    assert len(snake.body) == 2

    print("✓ 蛇的移动测试通过")

def test_collision_detection():
    """测试碰撞检测"""
    snake = Snake((10, 10))
    snake.body = [(10, 10), (10, 9), (10, 8)]

    # 测试墙壁碰撞
    snake.direction = (0, -1)
    snake.move()
    assert snake.check_collision(20, 20) == True

    # 测试自身碰撞
    snake.body = [(10, 10), (10, 9), (10, 8)]
    snake.direction = (0, 1)
    snake.move()
    assert snake.check_collision(20, 20) == True

    print("✓ 碰撞检测测试通过")

if __name__ == "__main__":
    test_snake_movement()
    test_collision_detection()

使用说明

  1. 安装pygame:pip install pygame
  2. 运行游戏:python snake_game.py
  3. 使用方向键控制蛇的移动
  4. 按空格键暂停/继续游戏
  5. 按ESC键退出游戏

扩展建议

  1. 添加关卡系统:不同的关卡有不同的地图和难度
  2. 多人游戏:支持双人游戏,一个键盘控制两条蛇
  3. 道具系统:添加各种道具增加游戏趣味性
  4. 存档功能:保存游戏进度
  5. 皮肤系统:选择不同的蛇和食物外观
  6. 成就系统:完成特定目标获得成就
  7. 排行榜:在线排行榜功能
  8. 移动端支持:移植到移动平台

学习要点

通过这个项目,你将学习到:

  1. 游戏开发基础:游戏循环、事件处理
  2. pygame框架:图形绘制、声音处理
  3. 面向对象编程:游戏对象的设计
  4. 算法应用:碰撞检测、路径规划
  5. 状态管理:游戏状态的控制
  6. 用户交互:键盘、鼠标输入处理
  7. 性能优化:帧率控制、资源管理

相关资源


开始制作你的游戏吧! 从基础版本开始,逐步添加更多功能。祝你游戏开发愉快!