Python版贪吃蛇保姆级教程

Python版贪吃蛇(最后附上完整代码并有详细注释):从零开始用Pygame实现经典游戏

一、前言:童年经典游戏重生

贪吃蛇作为一款经典游戏,承载着无数人的童年回忆。今天我们将用Python+pygame从零开始实现这个经典游戏!通过本教程,你不仅能掌握游戏开发的基本流程,还能学习到实用的编程技巧。先来看看最终效果:

二、开发准备

环境要求

  • Python 3.9

  • Pygame==2.6.1库(pip install pygame==2.6.1)

三、核心代码解析

3.1 游戏初始化

# 初始化Pygame引擎
pygame.init()

# 创建游戏窗口
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("贪吃蛇大作战")

3.2 游戏常量配置

WINDOW_WIDTH = 800   # 窗口宽度
WINDOW_HEIGHT = 600  # 窗口高度
CELL_SIZE = 20       # 蛇身和食物的单位尺寸
COLORS = {           # 颜色字典
    "BLACK": (0,0,0),
    "WHITE": (255,255,255),
    "RED": (255,0,0),
    # ...其他颜色
}

3.3 蛇的移动控制

# 方向向量控制:通过元组存储方向
current_dir = (1, 0)  # 初始向右

# 键盘事件处理(防止180度转向)
if event.key == pygame.K_UP:
    new_dir = (0, -1)
# 判断新方向是否合法(非相反方向)
if (current_dir[0] + new_dir[0] != 0) or ...:
    current_dir = new_dir

四、关键技术实现

4.1 蛇身绘制技巧

# 渐变颜色区分头身
for i, (x, y) in enumerate(snake):
    color = COLORS["SNAKE_HEAD"] if i==0 else COLORS["SNAKE_BODY"]
    # 圆角矩形提升美观度
    pygame.draw.rect(screen, color, (x,y,CELL_SIZE-1,CELL_SIZE-1), border_radius=4)

4.2 智能食物生成

def generate_food():
    while True:
        # 随机生成坐标
        x = random.randint(0, (WIDTH-CELL_SIZE)//CELL_SIZE) * CELL_SIZE
        y = ... 
        # 确保不在蛇身上
        if (x,y) not in snake:
            return (x,y)

4.3 碰撞检测系统

# 边界检测
new_head[0] < 0 or new_head[0] >= WIDTH...

# 自碰检测
new_head in snake

# 食物碰撞检测
new_head == food_pos

五、特色功能实现

5.1 速度切换系统

# 按住方向键加速
accelerate = any(keys[k] for k in (pygame.K_UP, ...))
# 动态调整帧率
Clock().tick(ACCELERATE_FPS if accelerate else BASE_FPS)

5.2 高分记录系统

def load_highscore():
    try:
        with open('highscore.txt') as f:
            return int(f.read())
    except:
        return 0

def save_highscore():
    with open('highscore.txt', 'w') as f:
        f.write(str(high_score))

六、游戏逻辑流程图

graph TD
    A[游戏初始化] --> B[主循环]
    B --> C{事件处理}
    C -->|按键| D[更新方向]
    C -->|退出| E[结束游戏]
    B --> F[移动蛇头]
    F --> G{碰撞检测}
    G -->|碰墙/自身| H[游戏结束]
    G -->|吃到食物| I[增长蛇身]
    G -->|正常移动| J[更新位置]
    B --> K[重绘画面]

扩展方向

  1. 增加不同难度级别

  2. 添加多种特殊食物(加速、减速等)

  3. 实现多人对战模式

  4. 加入背景音乐和音效

七、总结

通过本教程,我们完整实现了:

  • 游戏窗口创建与绘制

  • 蛇的移动与控制逻辑

  • 智能食物生成系统

  • 完善的碰撞检测

  • 高分记录功能

  • 动态速度调节

八、完整代码

# -*- coding: utf-8 -*-
import pygame
import random
import sys

# 初始化pygame(必须的步骤,用于初始化所有pygame模块)
pygame.init()

# === 游戏常量配置 ===
WINDOW_WIDTH = 800  # 游戏窗口宽度(单位:像素)
WINDOW_HEIGHT = 600  # 游戏窗口高度(单位:像素)
CELL_SIZE = 20  # 网格单元格大小(单位:像素)
BASE_FPS = 5  # 基础游戏帧率(控制蛇的正常移动速度)
ACCELERATE_FPS = 14  # 加速时的游戏帧率

# 颜色定义(RGB格式)
COLORS = {
    "BLACK": (0, 0, 0),
    "WHITE": (255, 255, 255),
    "RED": (255, 0, 0),
    "GREEN": (0, 255, 0),
    "BLUE": (0, 100, 200),
    "GRID": (40, 40, 40),  # 网格线颜色
    "SNAKE_HEAD": (0, 255, 0),  # 蛇头颜色
    "SNAKE_BODY": (0, 200, 0)  # 蛇身颜色
}

# === 游戏状态初始化 ===
snake = []  # 用列表存储蛇身体的坐标(每个元素是一个元组)
current_dir = (1, 0)  # 当前移动方向(使用向量表示,初始向右)
food_pos = (0, 0)  # 食物位置坐标
is_playing = True  # 游戏是否进行中的状态
score = 0  # 当前游戏分数
high_score = 0  # 历史最高分记录

# 初始化游戏窗口
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("贪吃蛇大作战")  # 窗口标题


def draw_grid():
    """绘制网格线背景,帮助玩家更好地观察位置"""
    # 绘制垂直网格线
    for x in range(0, WINDOW_WIDTH, CELL_SIZE):
        pygame.draw.line(screen, COLORS["GRID"], (x, 0), (x, WINDOW_HEIGHT))
    # 绘制水平网格线
    for y in range(0, WINDOW_HEIGHT, CELL_SIZE):
        pygame.draw.line(screen, COLORS["GRID"], (0, y), (WINDOW_WIDTH, y))


def generate_food():
    """生成食物坐标,确保不在蛇身体上"""
    while True:
        # 计算网格坐标(确保在窗口范围内)
        x = random.randint(0, (WINDOW_WIDTH - CELL_SIZE) // CELL_SIZE) * CELL_SIZE
        y = random.randint(0, (WINDOW_HEIGHT - CELL_SIZE) // CELL_SIZE) * CELL_SIZE
        # 检查生成位置是否与蛇身体重叠
        if (x, y) not in snake:
            return (x, y)


def reset_game():
    """重置游戏所有状态到初始值"""
    global snake, current_dir, food_pos, is_playing, score
    snake = [(WINDOW_WIDTH // 2, WINDOW_HEIGHT // 2)]  # 蛇初始位置在窗口中心
    current_dir = (1, 0)  # 初始方向向右
    food_pos = generate_food()  # 生成第一个食物
    is_playing = True  # 游戏状态设置为进行中
    score = 0  # 重置当前分数


def show_text(content, size, color, position):
    """在指定位置显示文字的工具函数"""
    font = pygame.font.SysFont('simhei', size)  # 使用黑体字
    text_surface = font.render(content, True, color)
    screen.blit(text_surface, position)


def load_highscore():
    """从文件读取历史最高分"""
    try:
        with open('highscore.txt', 'r') as f:
            return int(f.read())
    except FileNotFoundError:
        return 0  # 文件不存在时返回0分


def save_highscore():
    """保存最高分到文件"""
    with open('highscore.txt', 'w') as f:
        f.write(str(high_score))


# 初始化游戏
high_score = load_highscore()
reset_game()

# === 主游戏循环 ===
while True:
    # 处理事件队列(包括按键、窗口关闭等)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # 点击窗口关闭按钮
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:  # Q键退出
                pygame.quit()
                sys.exit()
            if event.key == pygame.K_r and not is_playing:  # R键重启游戏
                reset_game()
            # 方向键控制(已解决反向问题)
            if is_playing:
                new_dir = current_dir  # 默认保持当前方向
                if event.key == pygame.K_UP:
                    new_dir = (0, -1)
                elif event.key == pygame.K_DOWN:
                    new_dir = (0, 1)
                elif event.key == pygame.K_LEFT:
                    new_dir = (-1, 0)
                elif event.key == pygame.K_RIGHT:
                    new_dir = (1, 0)
                # 禁止直接反向(只有当新方向不相反时更新)
                if (current_dir[0] + new_dir[0] != 0) or (current_dir[1] + new_dir[1] != 0):
                    current_dir = new_dir

    # 获取当前按键状态实现加速功能
    keys = pygame.key.get_pressed()
    # 检查是否有方向键被按住(使用位运算优化判断)
    accelerate = any(keys[k] for k in (pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT))

    # 游戏进行中的逻辑处理
    if is_playing:
        # 计算新蛇头位置
        head_x, head_y = snake[0]
        dir_x, dir_y = current_dir
        new_head = (head_x + dir_x * CELL_SIZE, head_y + dir_y * CELL_SIZE)

        # 碰撞检测(边界和自身)
        if (new_head in snake or
                new_head[0] < 0 or
                new_head[0] >= WINDOW_WIDTH or
                new_head[1] < 0 or
                new_head[1] >= WINDOW_HEIGHT):
            is_playing = False
            # 更新最高分记录
            if score > high_score:
                high_score = score
                save_highscore()

        # 更新蛇的位置
        snake.insert(0, new_head)
        if new_head == food_pos:  # 吃到食物
            score += 10
            food_pos = generate_food()
        else:  # 没吃到食物时移除尾部
            snake.pop()

    # === 绘制游戏画面 ===
    screen.fill(COLORS["BLACK"])  # 填充背景色
    draw_grid()  # 绘制网格线

    # 绘制蛇的身体(使用渐变颜色)
    for i, (x, y) in enumerate(snake):
        # 根据部位设置颜色(头部更亮)
        color = COLORS["SNAKE_HEAD"] if i == 0 else COLORS["SNAKE_BODY"]
        # 绘制带圆角的蛇身
        pygame.draw.rect(screen, color, (x, y, CELL_SIZE - 1, CELL_SIZE - 1), border_radius=4)

    # 绘制食物(使用圆形)
    center = (food_pos[0] + CELL_SIZE // 2, food_pos[1] + CELL_SIZE // 2)
    pygame.draw.circle(screen, COLORS["RED"], center, CELL_SIZE // 2 - 2)

    # 显示分数信息
    show_text(f"分数: {score}  最高分: {high_score}", 24, COLORS["WHITE"], (10, 10))

    # 游戏结束显示提示
    if not is_playing:
        text_width = 400  # 根据文字长度估算居中位置
        show_text("游戏结束!按 R 重新开始", 48, COLORS["WHITE"],
                  (WINDOW_WIDTH // 2 - text_width // 2, WINDOW_HEIGHT // 2 - 30))

    # 更新画面并控制游戏速度
    pygame.display.update()
    # 根据加速状态动态调整帧率
    pygame.time.Clock().tick(ACCELERATE_FPS if accelerate else BASE_FPS)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值