Python pygame贪吃蛇游戏开发:从零到200行代码的完整实现

1. 环境准备与Pygame基础

要开发贪吃蛇游戏,首先需要搭建Python开发环境。我推荐使用Python 3.8+版本,这个版本对Pygame库的兼容性最好。安装Pygame只需要一行命令:

pip install pygame

安装完成后,可以创建一个简单的测试脚本来验证是否安装成功:

import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Pygame测试")
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.fill((255, 255, 255))
    pygame.display.flip()
pygame.quit()

这个基础框架展示了Pygame的核心工作流程:初始化、创建窗口、事件循环和渲染。在贪吃蛇游戏中,我们会在这个基础上添加更多功能模块。

Pygame的坐标系以左上角为原点(0,0),x轴向右增加,y轴向下增加。这个坐标系系统在定位游戏元素时非常重要。游戏中的每个"帧"都会重新绘制整个画面,通过快速连续的画面更新来产生动画效果。

2. 游戏核心架构设计

贪吃蛇游戏的核心逻辑可以分为几个关键模块:蛇的移动控制、食物生成、碰撞检测和游戏状态管理。我们先来看蛇的数据结构设计。

蛇的身体可以用一个双端队列(deque)来存储,这样在头部添加新节点和在尾部删除节点的操作都非常高效:

from collections import deque

snake = deque([(10, 5), (9, 5), (8, 5)])  # 初始蛇身
direction = (1, 0)  # 初始向右移动

def move_snake():
    head_x, head_y = snake[0]
    new_head = (head_x + direction[0], head_y + direction[1])
    snake.appendleft(new_head)  # 在头部添加新位置
    snake.pop()  # 删除尾部位置

食物生成需要考虑不与蛇身重叠:

def generate_food():
    while True:
        food_pos = (random.randint(0, 19), random.randint(0, 19))
        if food_pos not in snake:
            return food_pos

游戏主循环的基本结构如下:

clock = pygame.time.Clock()
FPS = 10  # 控制游戏速度

while True:
    # 处理输入事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            # 处理方向键改变方向
    
    # 游戏逻辑更新
    move_snake()
    check_collision()
    
    # 渲染
    draw_background()
    draw_snake()
    draw_food()
    
    pygame.display.flip()
    clock.tick(FPS)  # 控制帧率

3. 蛇的移动与控制实现

蛇的移动控制是游戏的核心机制之一。我们需要处理玩家的输入,并确保蛇的移动方向变化是合理的(不能直接180度转向)。

首先定义方向常量:

UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)

方向控制逻辑需要注意防止直接反向移动:

direction = RIGHT  # 初始方向

for event in pygame.event.get():
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_UP and direction != DOWN:
            direction = UP
        elif event.key == pygame.K_DOWN and direction != UP:
            direction = DOWN
        elif event.key == pygame.K_LEFT and direction != RIGHT:
            direction = LEFT
        elif event.key == pygame.K_RIGHT and direction != LEFT:
            direction = RIGHT

蛇的移动需要处理吃到食物时增长的情况:

def move_snake():
    head_x, head_y = snake[0]
    new_head = (head_x + direction[0], head_y + direction[1])
    snake.appendleft(new_head)
    
    # 如果没吃到食物,删除尾部
    if new_head != food_pos:
        snake.pop()
    else:
        # 生成新食物
        food_pos = generate_food()
        # 增加分数
        global score
        score += 10

为了让游戏体验更好,可以随着分数增加逐渐提高游戏速度:

if score % 100 == 0 and score > 0:
    FPS += 1  # 每100分加速一次

4. 碰撞检测与游戏逻辑

碰撞检测包括与边界、自身以及食物的碰撞。边界检测相对简单:

def check_boundary_collision():
    head = snake[0]
    if head[0] < 0 or head[0] >= GRID_WIDTH or head[1] < 0 or head[1] >= GRID_HEIGHT:
        return True
    return False

自身碰撞检测需要检查头部是否与身体其他部分重叠:

def check_self_collision():
    head = snake[0]
    for segment in list(snake)[1:]:
        if head == segment:
            return True
    return False

食物碰撞检测已经在move_snake函数中实现。当检测到碰撞时,需要处理游戏结束逻辑:

def game_over():
    font = pygame.font.SysFont('Arial', 50)
    text = font.render('Game Over!', True, (255, 0, 0))
    screen.blit(text, (WIDTH//2 - text.get_width()//2, HEIGHT//2 - text.get_height()//2))
    pygame.display.flip()
    pygame.time.wait(2000)  # 显示2秒
    reset_game()

游戏重置函数需要将所有状态恢复到初始值:

def reset_game():
    global snake, direction, food_pos, score, FPS
    snake = deque([(10, 5), (9, 5), (8, 5)])
    direction = RIGHT
    food_pos = generate_food()
    score = 0
    FPS = 10

5. 游戏界面渲染与优化

游戏视觉效果对用户体验至关重要。我们先定义一些颜色常量:

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)

绘制蛇身时,可以让头部和身体有视觉区分:

def draw_snake():
    for i, (x, y) in enumerate(snake):
        rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
        if i == 0:  # 头部
            pygame.draw.rect(screen, BLUE, rect)
        else:  # 身体
            pygame.draw.rect(screen, GREEN, rect)
            pygame.draw.rect(screen, BLACK, rect, 1)  # 边框

食物可以设计得更醒目一些:

def draw_food():
    x, y = food_pos
    center = (x * CELL_SIZE + CELL_SIZE//2, y * CELL_SIZE + CELL_SIZE//2)
    pygame.draw.circle(screen, RED, center, CELL_SIZE//2)

添加分数显示和游戏状态提示:

def draw_hud():
    font = pygame.font.SysFont('Arial', 20)
    score_text = font.render(f'Score: {score}', True, WHITE)
    fps_text = font.render(f'Speed: {FPS}', True, WHITE)
    screen.blit(score_text, (10, 10))
    screen.blit(fps_text, (10, 30))
    
    # 暂停提示
    if paused:
        pause_text = font.render('PAUSED - Press SPACE to continue', True, WHITE)
        screen.blit(pause_text, (WIDTH//2 - pause_text.get_width()//2, 10))

6. 完整代码实现与优化建议

将以上各部分组合起来,就得到了完整的贪吃蛇游戏。以下是完整的代码结构:

import pygame
import sys
import random
from collections import deque

# 初始化
pygame.init()

# 常量定义
CELL_SIZE = 20
GRID_WIDTH, GRID_HEIGHT = 30, 20
WIDTH, HEIGHT = CELL_SIZE * GRID_WIDTH, CELL_SIZE * GRID_HEIGHT

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

# 方向
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)

# 游戏状态
snake = deque([(10, 5), (9, 5), (8, 5)])
direction = RIGHT
food_pos = (15, 10)
score = 0
FPS = 10
paused = False

# 初始化屏幕
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('贪吃蛇')
clock = pygame.time.Clock()

def generate_food():
    while True:
        food_pos = (random.randint(0, GRID_WIDTH-1), random.randint(0, GRID_HEIGHT-1))
        if food_pos not in snake:
            return food_pos

def move_snake():
    global food_pos, score, FPS
    head_x, head_y = snake[0]
    new_head = (head_x + direction[0], head_y + direction[1])
    snake.appendleft(new_head)
    
    if new_head == food_pos:
        food_pos = generate_food()
        score += 10
        if score % 100 == 0:
            FPS += 1
    else:
        snake.pop()

def check_collision():
    head = snake[0]
    # 边界检测
    if (head[0] < 0 or head[0] >= GRID_WIDTH or 
        head[1] < 0 or head[1] >= GRID_HEIGHT):
        return True
    # 自身碰撞
    for segment in list(snake)[1:]:
        if head == segment:
            return True
    return False

def draw_game():
    screen.fill(BLACK)
    # 画网格
    for x in range(0, WIDTH, CELL_SIZE):
        pygame.draw.line(screen, (50, 50, 50), (x, 0), (x, HEIGHT))
    for y in range(0, HEIGHT, CELL_SIZE):
        pygame.draw.line(screen, (50, 50, 50), (0, y), (WIDTH, y))
    
    # 画蛇
    for i, (x, y) in enumerate(snake):
        rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
        if i == 0:
            pygame.draw.rect(screen, BLUE, rect)
        else:
            pygame.draw.rect(screen, GREEN, rect)
            pygame.draw.rect(screen, BLACK, rect, 1)
    
    # 画食物
    x, y = food_pos
    center = (x * CELL_SIZE + CELL_SIZE//2, y * CELL_SIZE + CELL_SIZE//2)
    pygame.draw.circle(screen, RED, center, CELL_SIZE//2)
    
    # 画HUD
    font = pygame.font.SysFont('Arial', 20)
    score_text = font.render(f'Score: {score}', True, WHITE)
    fps_text = font.render(f'Speed: {FPS}', True, WHITE)
    screen.blit(score_text, (10, 10))
    screen.blit(fps_text, (10, 30))
    
    if paused:
        pause_text = font.render('PAUSED - Press SPACE to continue', True, WHITE)
        screen.blit(pause_text, (WIDTH//2 - pause_text.get_width()//2, 10))
    
    pygame.display.flip()

def reset_game():
    global snake, direction, food_pos, score, FPS, paused
    snake = deque([(10, 5), (9, 5), (8, 5)])
    direction = RIGHT
    food_pos = generate_food()
    score = 0
    FPS = 10
    paused = False

def game_over():
    font = pygame.font.SysFont('Arial', 50)
    text = font.render('Game Over!', True, RED)
    screen.blit(text, (WIDTH//2 - text.get_width()//2, HEIGHT//2 - text.get_height()//2))
    pygame.display.flip()
    pygame.time.wait(2000)
    reset_game()

# 主循环
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP and direction != DOWN:
                direction = UP
            elif event.key == pygame.K_DOWN and direction != UP:
                direction = DOWN
            elif event.key == pygame.K_LEFT and direction != RIGHT:
                direction = LEFT
            elif event.key == pygame.K_RIGHT and direction != LEFT:
                direction = RIGHT
            elif event.key == pygame.K_SPACE:
                paused = not paused
            elif event.key == pygame.K_r:
                reset_game()
    
    if not paused:
        move_snake()
        if check_collision():
            game_over()
    
    draw_game()
    clock.tick(FPS)

pygame.quit()
sys.exit()

这个实现大约200行代码,包含了贪吃蛇游戏的所有核心功能。如果想进一步优化,可以考虑:

  1. 添加游戏音效和背景音乐
  2. 实现游戏开始界面和难度选择
  3. 添加特殊食物类型(加速、减速、加分等)
  4. 实现高分记录功能
  5. 优化视觉效果,如添加动画效果

在实际开发过程中,我发现使用双端队列(deque)来存储蛇身确实比普通列表(list)更高效,特别是在蛇变得很长时。另外,将游戏逻辑和渲染分离可以使代码更清晰,便于维护和扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值