贪吃蛇
import pygame
import random
import sys
import time
======================
游戏配置
======================
class GameConfig:
"""游戏配置参数"""
# 网格设置
GRID_SIZE = 20
GRID_WIDTH = 30
GRID_HEIGHT = 20
# 窗口大小
WIDTH = GRID_SIZE * GRID_WIDTH
HEIGHT = GRID_SIZE * GRID_HEIGHT
# 游戏速度
BASE_SPEED = 10 # 初始速度(帧率)
SPEED_INCREMENT = 1 # 每得多少分增加速度
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
GRAY = (100, 100, 100)
# 字体设置
FONT_SIZE = 36
FONT_SMALL_SIZE = 24
======================
初始化游戏
======================
def init_game():
"""初始化游戏"""
pygame.init()
pygame.display.init()
pygame.font.init()
win = pygame.display.set_mode((GameConfig.WIDTH, GameConfig.HEIGHT))
pygame.display.set_caption("贪吃蛇游戏")
font = pygame.font.Font(None, GameConfig.FONT_SIZE)
small_font = pygame.font.Font(None, GameConfig.FONT_SMALL_SIZE)
return win, font, small_font
======================
蛇类
======================
class Snake:
"""贪吃蛇游戏中的蛇"""
def __init__(self):
"""初始化蛇"""
# 计算中心位置
center_x, center_y = GameConfig.GRID_WIDTH // 2, GameConfig.GRID_HEIGHT // 2
self.body = [
(center_x, center_y),
(center_x - 1, center_y),
(center_x - 2, center_y)
]
self.direction = (1, 0) # 初始方向向右
self.last_direction = self.direction
self.grow_next_move = False # 标记是否需要增长
def change_direction(self, new_direction):
"""改变蛇的移动方向
参数:
new_direction (tuple): 新的方向向量 (x, y)
"""
# 防止蛇直接反向移动
if (new_direction[0] * -1, new_direction[1] * -1) != self.direction:
self.last_direction = self.direction
self.direction = new_direction
def move(self):
"""移动蛇"""
head_x, head_y = self.body[0]
new_head = (head_x + self.direction[0], head_y + self.direction[1])
self.body.insert(0, new_head)
if not self.grow_next_move:
self.body.pop() # 不增长则移除尾部
else:
self.grow_next_move = False # 重置增长标记
def check_collision(self):
"""检查蛇是否发生碰撞
返回:
bool: 如果发生碰撞返回True,否则返回False
"""
head = self.body[0]
# 边界碰撞检测
if (head[0] < 0 or head[0] >= GameConfig.GRID_WIDTH or
head[1] < 0 or head[1] >= GameConfig.GRID_HEIGHT):
return True
# 自身碰撞检测(从第二个身体节点开始检查)
if head in self.body[1:]:
return True
return False
def draw(self, win):
"""绘制蛇
参数:
win: pygame窗口对象
"""
for i, segment in enumerate(self.body):
# 蛇头用深绿色,身体用浅绿色
color = (0, 200, 0) if i == 0 else GameConfig.GREEN # 蛇头颜色加深
pygame.draw.rect(win, color,
(segment[0] * GameConfig.GRID_SIZE,
segment[1] * GameConfig.GRID_SIZE,
GameConfig.GRID_SIZE, GameConfig.GRID_SIZE))
# 绘制蛇身边框(黑色细线)
pygame.draw.rect(win, GameConfig.BLACK,
(segment[0] * GameConfig.GRID_SIZE,
segment[1] * GameConfig.GRID_SIZE,
GameConfig.GRID_SIZE, GameConfig.GRID_SIZE), 1)
======================
食物类
======================
class Food:
"""贪吃蛇游戏中的食物"""
def __init__(self, snake):
"""初始化食物
参数:
snake: 蛇对象,用于确保食物不会生成在蛇身上
"""
self.position = self.generate_new_position(snake)
self.spawn_time = time.time() # 记录生成时间(用于未来扩展)
def generate_new_position(self, snake):
"""生成新的食物位置
参数:
snake: 蛇对象
返回:
tuple: 新的食物位置 (x, y)
"""
while True:
x = random.randint(0, GameConfig.GRID_WIDTH - 1)
y = random.randint(0, GameConfig.GRID_HEIGHT - 1)
if (x, y) not in snake.body: # 确保不在蛇身上
return x, y
def draw(self, win):
"""绘制食物
参数:
win: pygame窗口对象
"""
# 绘制食物主体(红色)
pygame.draw.rect(win, GameConfig.RED,
(self.position[0] * GameConfig.GRID_SIZE,
self.position[1] * GameConfig.GRID_SIZE,
GameConfig.GRID_SIZE, GameConfig.GRID_SIZE))
# 绘制食物高光(白色小方块)
highlight_size = GameConfig.GRID_SIZE // 3
pygame.draw.rect(win, GameConfig.WHITE,
(self.position[0] * GameConfig.GRID_SIZE + 2,
self.position[1] * GameConfig.GRID_SIZE + 2,
highlight_size, highlight_size))
======================
游戏功能函数
======================
def draw_grid(win):
"""绘制网格背景
参数:
win: pygame窗口对象
"""
for x in range(0, GameConfig.WIDTH, GameConfig.GRID_SIZE):
pygame.draw.line(win, GameConfig.GRAY, (x, 0), (x, GameConfig.HEIGHT), 1) # 水平线
for y in range(0, GameConfig.HEIGHT, GameConfig.GRID_SIZE):
pygame.draw.line(win, GameConfig.GRAY, (0, y), (GameConfig.WIDTH, y), 1) # 垂直线
def draw_score(score, win, font):
"""绘制得分
参数:
score (int): 当前得分
win: pygame窗口对象
font: 字体对象
"""
score_text = font.render(f"得分: {score}", True, GameConfig.WHITE)
win.blit(score_text, (10, 10)) # 左上角显示得分
def show_game_over(score, win, font, small_font):
"""显示游戏结束界面
参数:
score (int): 最终得分
win: pygame窗口对象
font: 主字体对象
small_font: 小字体对象
"""
win.fill(GameConfig.BLACK)
# 游戏结束标题
game_over_text = font.render("GAME OVER", True, GameConfig.WHITE)
game_over_rect = game_over_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2 - 50))
win.blit(game_over_text, game_over_rect)
# 最终得分
score_text = font.render(f"最终得分: {score}", True, GameConfig.WHITE)
score_rect = score_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2))
win.blit(score_text, score_rect)
# 提示信息(小字体)
restart_text = small_font.render("按 R 键重新开始", True, GameConfig.WHITE)
restart_rect = restart_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2 + 40))
win.blit(restart_text, restart_rect)
quit_text = small_font.render("按 Q 键退出游戏", True, GameConfig.WHITE)
quit_rect = quit_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2 + 70))
win.blit(quit_text, quit_rect)
pygame.display.update()
def pause_game(win, font):
"""暂停游戏
参数:
win: pygame窗口对象
font: 字体对象
"""
paused = True
while paused:
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_p: # 按P键继续
paused = False
elif event.key == pygame.K_q: # 按Q键退出
pygame.quit()
sys.exit()
# 绘制暂停界面
win.fill(GameConfig.BLACK)
pause_text = font.render("游戏暂停", True, GameConfig.WHITE)
pause_rect = pause_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2))
win.blit(pause_text, pause_rect)
continue_text = font.render("按 P 继续游戏", True, GameConfig.WHITE)
continue_rect = continue_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2 + 40))
win.blit(continue_text, continue_rect)
quit_text = font.render("按 Q 退出游戏", True, GameConfig.WHITE)
quit_rect = quit_text.get_rect(center=(GameConfig.WIDTH // 2, GameConfig.HEIGHT // 2 + 80))
win.blit(quit_text, quit_rect)
pygame.display.update()
======================
游戏主循环
======================
def game_loop(win, font, small_font):
"""游戏主循环
参数:
win: pygame窗口对象
font: 主字体对象
small_font: 小字体对象
返回:
bool: 游戏是否正常结束(未崩溃)
"""
snake = Snake()
food = Food(snake)
score = 0
clock = pygame.time.Clock()
game_over = False
while not game_over:
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in [pygame.K_w, pygame.K_UP, pygame.K_i]:
snake.change_direction((0, -1)) # 向上
elif event.key in [pygame.K_s, pygame.K_DOWN, pygame.K_k]:
snake.change_direction((0, 1)) # 向下
elif event.key in [pygame.K_a, pygame.K_LEFT, pygame.K_j]:
snake.change_direction((-1, 0)) # 向左
elif event.key in [pygame.K_d, pygame.K_RIGHT, pygame.K_l]:
snake.change_direction((1, 0)) # 向右
elif event.key == pygame.K_p: # 暂停/继续
pause_game(win, font)
# 移动蛇
grow = False
if snake.body[0] == food.position:
score += 1
grow = True
snake.grow_next_move = True # 标记需要增长
food = Food(snake) # 生成新食物
snake.move() # 执行移动
# 碰撞检测
if snake.check_collision():
show_game_over(score, win, font, small_font)
return False # 游戏结束(非正常退出)
# 绘制界面
win.fill(GameConfig.BLACK)
draw_grid(win) # 绘制网格背景
snake.draw(win) # 绘制蛇
food.draw(win) # 绘制食物
draw_score(score, win, font) # 绘制得分
# 调整游戏速度(分数越高,速度越快)
speed = GameConfig.BASE_SPEED + (score // GameConfig.SPEED_INCREMENT)
clock.tick(speed) # 控制帧率
pygame.display.update() # 更新屏幕
return True # 游戏正常结束(未崩溃)
======================
主函数
======================
def main():
"""游戏主函数"""
win, font, small_font = init_game() # 初始化游戏窗口和字体
while True:
# 运行一局游戏
game_result = game_loop(win, font, small_font)
# 游戏结束后等待用户操作
if not game_result: # 游戏异常结束(如碰撞)
waiting = True
while waiting:
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_r: # 按R键重新开始
waiting = False
elif event.key == pygame.K_q: # 按Q键退出
pygame.quit()
sys.exit()
if name == "main":
main() # 启动游戏

浙公网安备 33010602011771号