【Python小游戏】用 Python 实现经典贪吃蛇游戏,详细小白保姆级(包含程序源代码)

该文章已生成可运行项目,


前言

下面是最终运行的效果图,这个用简单一个三个类实现这个小游戏,用到了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()

运行程序即可开始游戏,使用方向键控制蛇的移动,吃到红色食物得分,撞到墙壁或自身则游戏结束。

功能扩展建议

  1. 增加特殊食物:随机生成具有限时效果的特殊食物(如加速、减速、额外分数等)
  2. 音效系统:添加移动、吃食物、游戏结束等音效
  3. 排行榜:记录玩家的最高分数
  4. 自定义难度:允许玩家选择初始速度和关卡设置
  5. 皮肤系统:提供不同的蛇和食物外观选择

五、总结

本文实现了一个功能完整的贪吃蛇游戏,通过面向对象的方式将游戏元素模块化,使代码结构清晰、易于维护和扩展。核心难点在于蛇的移动逻辑和碰撞检测,通过合理的数据结构(列表存储蛇身)和算法(头部添加与尾部移除)实现了流畅的游戏体验。

这个项目非常适合Python初学者练习面向对象编程和游戏开发基础,通过不断扩展功能可以深入理解游戏开发的核心原理。

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值