Python版贪吃蛇保姆级教程

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[重绘画面]

扩展方向

增加不同难度级别

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

实现多人对战模式

加入背景音乐和音效

七、总结

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

游戏窗口创建与绘制

蛇的移动与控制逻辑

智能食物生成系统

完善的碰撞检测

高分记录功能

动态速度调节

八、完整代码

# -*- 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)

相关推荐

如何在Keynote 讲演中添加神奇移动效果?新手教程
365沙巴体育入口

如何在Keynote 讲演中添加神奇移动效果?新手教程

📅 09-28 👁️ 5233
世界杯丨2022卡塔尔世界杯32强巡礼
365沙巴体育入口

世界杯丨2022卡塔尔世界杯32强巡礼

📅 09-09 👁️ 7178
麻歌词 – 卦者灵风
365彩票下载1.0.0老版本

麻歌词 – 卦者灵风

📅 08-24 👁️ 2701
人民日报海外版
365彩票下载1.0.0老版本

人民日报海外版

📅 08-25 👁️ 6744
王者荣耀李白皮肤千年之狐上架时间与价格揭秘
365彩票下载1.0.0老版本

王者荣耀李白皮肤千年之狐上架时间与价格揭秘

📅 07-28 👁️ 874
'溱'字用粤语广东话点读(怎么读)
365沙巴体育入口

'溱'字用粤语广东话点读(怎么读)

📅 07-15 👁️ 7820
PSV破解流程+软件游戏安装(最简单/最快的方法整理,已测支持3.65~3.68,理论上支持全系列版本)
小米手环和乐心手环对比:哪个更适合你?
365速发国际平台app下载

小米手环和乐心手环对比:哪个更适合你?

📅 08-23 👁️ 1195
《命运方舟》魔方前置任务在哪?魔方前置任务介绍
365彩票下载1.0.0老版本

《命运方舟》魔方前置任务在哪?魔方前置任务介绍

📅 08-10 👁️ 3263