📚 前言
编程基础第一期《10-30》--贪吃蛇游戏教程,贪吃蛇是一款经典的休闲游戏,也是Python初学者进阶的绝佳练习项目。本教程将详细讲解如何使用Python的pygame库开发一个完整的贪吃蛇游戏,并解析其中涉及的编程知识点。
🛠️ 开发环境准备
- Python 3.6+
- Pygame库
安装pygame库:
pip install pygame
🧩 游戏核心概念
1. 游戏循环
贪吃蛇游戏基于一个主循环,包括:
- 处理用户输入
- 更新游戏状态
- 渲染画面
2. 坐标系统
我们使用网格坐标系统,将游戏区域划分为若干个方格,蛇和食物都占据其中的格子。
3. 碰撞检测
需要检测:
- 蛇头是否碰到墙壁
- 蛇头是否碰到自己的身体
- 蛇头是否碰到食物
💡 代码实现与知识点解析
1. 导入必要的库
import pygame
import sys
import random
import time
知识点:
pygame:Python游戏开发库,提供图形、声音、输入等功能sys:系统相关功能,用于退出程序random:生成随机数,用于食物的随机位置time:时间相关功能,用于控制游戏速度
2. 初始化游戏设置
# 初始化pygame
pygame.init()
# 颜色定义 (R, G, B)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
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
SNAKE_SPEED = 10 # 帧率控制
# 方向常量
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
知识点:
- 常量定义:使用全大写变量名表示常量
- RGB颜色模型:使用三元组表示颜色
- 整除运算符(
//):确保网格大小为整数 - 元组表示方向:使用二维向量表示移动方向
3. 创建游戏窗口
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Python贪吃蛇')
clock = pygame.time.Clock()
知识点:
pygame.display.set_mode:创建游戏窗口pygame.display.set_caption:设置窗口标题pygame.time.Clock:创建时钟对象,用于控制游戏帧率
4. 定义蛇类
class Snake:
def __init__(self):
self.positions = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)] # 蛇身体位置列表,初始在屏幕中央
self.direction = RIGHT # 初始方向向右
self.next_direction = RIGHT # 下一步方向
self.grow = False # 是否增长
def get_head_position(self):
return self.positions[0] # 获取蛇头位置
def update(self):
# 更新方向
self.direction = self.next_direction
# 获取蛇头位置
head = self.get_head_position()
# 计算新的蛇头位置
new_x = (head[0] + self.direction[0]) % GRID_WIDTH
new_y = (head[1] + self.direction[1]) % GRID_HEIGHT
new_head = (new_x, new_y)
# 检查是否碰到自己
if new_head in self.positions[1:]:
return False # 游戏结束
# 添加新的蛇头
self.positions.insert(0, new_head)
# 如果不需要增长,则移除蛇尾
if not self.grow:
self.positions.pop()
else:
self.grow = False
return True # 继续游戏
def change_direction(self, direction):
# 防止直接反向移动
if (direction[0] * -1, direction[1] * -1) == self.direction:
return
self.next_direction = direction
def grow_snake(self):
self.grow = True
def draw(self, surface):
for i, pos in enumerate(self.positions):
color = GREEN if i == 0 else BLUE # 蛇头绿色,身体蓝色
rect = pygame.Rect(pos[0] * GRID_SIZE, pos[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, color, rect)
pygame.draw.rect(surface, BLACK, rect, 1) # 绘制网格边框
知识点:
- 类的定义与实例化:面向对象编程
- 列表操作:
insert添加元素,pop移除元素 - 模运算(
%):实现穿墙效果 - 条件判断:检查碰撞和方向变化
- 绘图函数:使用
pygame.draw.rect绘制矩形
5. 定义食物类
class Food:
def __init__(self):
self.position = (0, 0)
self.randomize_position()
def randomize_position(self):
self.position = (random.randint(0, GRID_WIDTH - 1),
random.randint(0, GRID_HEIGHT - 1))
def draw(self, surface):
rect = pygame.Rect(self.position[0] * GRID_SIZE,
self.position[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, RED, rect)
pygame.draw.rect(surface, BLACK, rect, 1)
知识点:
- 随机数生成:使用
random.randint生成随机整数 - 类的方法:定义类的行为
6. 游戏主循环
def main():
snake = Snake()
food = Food()
score = 0
game_over = False
# 游戏主循环
while True:
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if game_over:
if event.key == pygame.K_RETURN:
# 重新开始游戏
snake = Snake()
food = Food()
score = 0
game_over = False
else:
# 方向控制
if event.key == pygame.K_UP:
snake.change_direction(UP)
elif event.key == pygame.K_DOWN:
snake.change_direction(DOWN)
elif event.key == pygame.K_LEFT:
snake.change_direction(LEFT)
elif event.key == pygame.K_RIGHT:
snake.change_direction(RIGHT)
if not game_over:
# 更新游戏状态
if not snake.update():
game_over = True
# 检查是否吃到食物
if snake.get_head_position() == food.position:
snake.grow_snake()
food.randomize_position()
# 确保食物不出现在蛇身上
while food.position in snake.positions:
food.randomize_position()
score += 1
# 绘制游戏画面
screen.fill(BLACK)
snake.draw(screen)
food.draw(screen)
# 显示分数
font = pygame.font.SysFont('arial', 20)
score_text = font.render(f'得分: {score}', True, WHITE)
screen.blit(score_text, (10, 10))
# 游戏结束显示
if game_over:
font = pygame.font.SysFont('arial', 50)
game_over_text = font.render('游戏结束!', True, WHITE)
restart_text = font.render('按回车键重新开始', True, WHITE)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 50))
screen.blit(restart_text, (SCREEN_WIDTH // 2 - 150, SCREEN_HEIGHT // 2 + 10))
# 更新屏幕
pygame.display.update()
clock.tick(SNAKE_SPEED) # 控制游戏速度
if __name__ == "__main__":
main()
==总代码==
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Python贪吃蛇游戏
作者: Python游戏开发者
功能: 一个完整的贪吃蛇游戏,使用Pygame库开发
"""
import pygame
import sys
import random
import time
# 初始化pygame
pygame.init()
# 颜色定义 (R, G, B)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
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
SNAKE_SPEED = 10 # 帧率控制
# 方向常量
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Python贪吃蛇')
clock = pygame.time.Clock()
class Snake:
def __init__(self):
self.positions = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)] # 蛇身体位置列表,初始在屏幕中央
self.direction = RIGHT # 初始方向向右
self.next_direction = RIGHT # 下一步方向
self.grow = False # 是否增长
def get_head_position(self):
return self.positions[0] # 获取蛇头位置
def update(self):
# 更新方向
self.direction = self.next_direction
# 获取蛇头位置
head = self.get_head_position()
# 计算新的蛇头位置
new_x = (head[0] + self.direction[0]) % GRID_WIDTH
new_y = (head[1] + self.direction[1]) % GRID_HEIGHT
new_head = (new_x, new_y)
# 检查是否碰到自己
if new_head in self.positions[1:]:
return False # 游戏结束
# 添加新的蛇头
self.positions.insert(0, new_head)
# 如果不需要增长,则移除蛇尾
if not self.grow:
self.positions.pop()
else:
self.grow = False
return True # 继续游戏
def change_direction(self, direction):
# 防止直接反向移动
if (direction[0] * -1, direction[1] * -1) == self.direction:
return
self.next_direction = direction
def grow_snake(self):
self.grow = True
def draw(self, surface):
for i, pos in enumerate(self.positions):
color = GREEN if i == 0 else BLUE # 蛇头绿色,身体蓝色
rect = pygame.Rect(pos[0] * GRID_SIZE, pos[1] * GRID_SIZE, GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, color, rect)
pygame.draw.rect(surface, BLACK, rect, 1) # 绘制网格边框
class Food:
def __init__(self):
self.position = (0, 0)
self.randomize_position()
def randomize_position(self):
self.position = (random.randint(0, GRID_WIDTH - 1),
random.randint(0, GRID_HEIGHT - 1))
def draw(self, surface):
rect = pygame.Rect(self.position[0] * GRID_SIZE,
self.position[1] * GRID_SIZE,
GRID_SIZE, GRID_SIZE)
pygame.draw.rect(surface, RED, rect)
pygame.draw.rect(surface, BLACK, rect, 1)
def main():
snake = Snake()
food = Food()
score = 0
game_over = False
# 游戏主循环
while True:
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if game_over:
if event.key == pygame.K_RETURN:
# 重新开始游戏
snake = Snake()
food = Food()
score = 0
game_over = False
else:
# 方向控制
if event.key == pygame.K_UP:
snake.change_direction(UP)
elif event.key == pygame.K_DOWN:
snake.change_direction(DOWN)
elif event.key == pygame.K_LEFT:
snake.change_direction(LEFT)
elif event.key == pygame.K_RIGHT:
snake.change_direction(RIGHT)
if not game_over:
# 更新游戏状态
if not snake.update():
game_over = True
# 检查是否吃到食物
if snake.get_head_position() == food.position:
snake.grow_snake()
food.randomize_position()
# 确保食物不出现在蛇身上
while food.position in snake.positions:
food.randomize_position()
score += 1
# 绘制游戏画面
screen.fill(BLACK)
snake.draw(screen)
food.draw(screen)
# 显示分数
font = pygame.font.SysFont('arial', 20)
score_text = font.render(f'得分: {score}', True, WHITE)
screen.blit(score_text, (10, 10))
# 游戏结束显示
if game_over:
font = pygame.font.SysFont('arial', 50)
game_over_text = font.render('游戏结束!', True, WHITE)
restart_text = font.render('按回车键重新开始', True, WHITE)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 50))
screen.blit(restart_text, (SCREEN_WIDTH // 2 - 150, SCREEN_HEIGHT // 2 + 10))
# 更新屏幕
pygame.display.update()
clock.tick(SNAKE_SPEED) # 控制游戏速度
if __name__ == "__main__":
main()
知识点:
- 事件处理:捕获键盘输入和窗口关闭事件
- 游戏状态管理:跟踪游戏是否结束
- 碰撞检测:检查蛇头是否碰到食物
- 文本渲染:显示分数和游戏结束信息
- 主循环控制:使用时钟控制游戏帧率
if __name__ == "__main__"结构:确保代码作为主程序运行时才执行
🎮 游戏功能
-
基础玩法:
- 使用方向键控制蛇的移动
- 吃到食物后蛇身增长,得分增加
- 碰到自己身体游戏结束
- 支持穿墙功能
-
游戏界面:
- 显示当前得分
- 游戏结束提示
- 支持重新开始
🔍 进阶知识点
-
游戏循环模式:
- 输入处理 → 状态更新 → 渲染 → 循环
-
面向对象编程:
- 封装:将蛇和食物的属性和行为封装在类中
- 继承:可以扩展为更复杂的游戏对象
- 多态:不同对象可以有自己的绘制方法
-
碰撞检测算法:
- 基于网格的简单碰撞检测
-
状态管理:
- 游戏状态(进行中/结束)的管理
- 重置游戏状态
📝 总结
通过这个贪吃蛇游戏项目,我们学习了以下Python编程知识:
- Pygame库的基本使用
- 面向对象编程思想
- 游戏循环和状态管理
- 事件处理机制
- 碰撞检测算法
- 随机数生成
- 图形绘制和文本渲染
- 键盘输入处理
这个项目是Python游戏开发的良好起点,掌握了这些基础知识后,你可以尝试开发更复杂的游戏或者对现有游戏进行扩展。
💡 编程小贴士:游戏开发是学习编程的绝佳方式,它结合了算法、数据结构、图形、音频等多方面知识,同时能给你带来成就感和乐趣。