使用Pygame制作“贪吃蛇”游戏
创作时间:
作者:
@小白创作中心
使用Pygame制作“贪吃蛇”游戏
引用
CSDN
1.
https://blog.csdn.net/weixin_41793160/article/details/145405247
贪吃蛇是一款经典的休闲小游戏:玩家通过操控一条会不断变长的“蛇”在屏幕中移动,去吃随机出现的食物,同时要避免撞到墙壁或自己身体的其他部分。由于其逻辑相对简单,但可玩性和扩展性都不错,非常适合作为新手练习游戏编程的项目。在本篇博客中,我们将使用Python语言 +Pygame库来从零实现一款贪吃蛇。
开发环境准备
- Python 3.x
- Pygame库:如果尚未安装,请在命令行执行:
pip install pygame
- 图形界面环境:在常见的桌面系统(Windows、macOS、Linux)上都可以正常运行 Pygame 程序。
游戏实现思路
要实现一个简易的贪吃蛇,主要需要以下几个要点:
- 游戏界面
- 一般的做法是将屏幕拆分成网格(如 20×20 的方格),蛇和食物都在这些方格坐标上移动。
- 每一个方格的大小可定义为 20×20 或更适合你需求的像素。
- 蛇的运动每次走一格,方向由玩家通过箭头键或 WASD 控制。
- 蛇的表示
- 通常用一个列表来储存蛇身每个“方块”的坐标(从头到尾依次存放)。
- 当蛇移动时,需要在头部插入一个新的坐标(根据方向计算),同时移除最后一个坐标(蛇尾)来保持“长度”不变;只有当蛇吃到食物时,才不移除尾部,从而实现“变长”。
- 食物的产生
- 在网格上随机产生一个坐标点,作为食物。
- 当蛇头和食物坐标重合时,表示蛇吃到了食物,此时增加蛇的长度并在其他空格处随机生成新的食物。
- 边界与身体碰撞检测
- 边界检测:如果蛇头超出屏幕范围,则表示撞墙,游戏结束。
- 身体碰撞检测:如果蛇头的坐标跟身体某个方块相同,表示咬到自己,游戏结束。
- 游戏循环
- 使用 Pygame 的事件与时钟,循环更新游戏状态:接收玩家按键,移动蛇头,检测碰撞,更新得分等。
完整示例代码
将以下代码保存为
snake_game.py
并运行,即可体验一个最基本版本的贪吃蛇。你可以根据自己的需求对其中的参数或逻辑进行修改和完善。
import pygame
import random
import sys
# 初始化 Pygame
pygame.init()
# ---------------------
# 全局配置
# ---------------------
BLOCK_SIZE = 20 # 蛇和食物的大小(方块尺寸)
GRID_WIDTH = 30 # 水平方向方块数
GRID_HEIGHT = 20 # 垂直方向方块数
SCREEN_WIDTH = GRID_WIDTH * BLOCK_SIZE
SCREEN_HEIGHT = GRID_HEIGHT * BLOCK_SIZE
FPS = 10 # 游戏刷新率(蛇移动速度)
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 200, 0)
GRAY = (50, 50, 50)
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("贪吃蛇 - Pygame")
# 字体
font = pygame.font.SysFont("arial", 24)
# ---------------------
# 功能函数
# ---------------------
def draw_text(text, color, x, y):
"""在屏幕指定位置绘制文字"""
surface = font.render(text, True, color)
screen.blit(surface, (x, y))
def draw_block(color, x, y):
"""在(x, y)绘制一个BLOCK_SIZE大小的方块"""
rect = pygame.Rect(x, y, BLOCK_SIZE, BLOCK_SIZE)
pygame.draw.rect(screen, color, rect)
# ---------------------
# 蛇类
# ---------------------
class Snake:
def __init__(self):
# 蛇初始位置(列表: 记录蛇身每个方块的坐标)
# 例如[(x1, y1), (x2, y2), ...] 从头到尾
self.body = [(GRID_WIDTH // 2, GRID_HEIGHT // 2)]
self.direction = 'UP' # 初始方向:上
self.grow = False # 标识是否需要增长身体
def move(self):
# 计算新头部位置
head_x, head_y = self.body[0]
if self.direction == 'UP':
head_y -= 1
elif self.direction == 'DOWN':
head_y += 1
elif self.direction == 'LEFT':
head_x -= 1
elif self.direction == 'RIGHT':
head_x += 1
new_head = (head_x, head_y)
self.body.insert(0, new_head) # 头部插入到列表最前
# 如果不需要生长,则移除尾部
if not self.grow:
self.body.pop()
else:
self.grow = False # 本次已经完成增长
def change_direction(self, new_dir):
"""
根据玩家按键改变蛇的方向,
但需要防止蛇直接掉头(如当前在往左跑,不可立即改成往右)
"""
opposite = {'UP': 'DOWN', 'DOWN': 'UP', 'LEFT': 'RIGHT', 'RIGHT': 'LEFT'}
if new_dir != opposite[self.direction]:
self.direction = new_dir
def check_collision(self):
"""
检测是否撞墙或撞自己:
- 撞墙: 头部超出网格范围
- 撞自己: 头部坐标出现在身体其他部分
"""
head_x, head_y = self.body[0]
# 撞墙
if head_x < 0 or head_x >= GRID_WIDTH or head_y < 0 or head_y >= GRID_HEIGHT:
return True
# 撞自己
if self.body[0] in self.body[1:]:
return True
return False
def draw(self):
"""绘制蛇"""
for block in self.body:
x_coord = block[0] * BLOCK_SIZE
y_coord = block[1] * BLOCK_SIZE
draw_block(GREEN, x_coord, y_coord)
# ---------------------
# 食物类
# ---------------------
class Food:
def __init__(self):
self.position = self.random_pos()
def random_pos(self):
"""随机生成食物坐标(网格中)"""
return (random.randint(0, GRID_WIDTH - 1),
random.randint(0, GRID_HEIGHT - 1))
def draw(self):
"""绘制食物"""
x_coord = self.position[0] * BLOCK_SIZE
y_coord = self.position[1] * BLOCK_SIZE
draw_block(RED, x_coord, y_coord)
# ---------------------
# 游戏主函数
# ---------------------
def main():
clock = pygame.time.Clock()
snake = Snake()
food = Food()
score = 0
running = True
while running:
clock.tick(FPS) # 控制游戏帧率(蛇移动速度)
# 1) 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
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')
# 2) 更新游戏状态 (蛇移动, 检测碰撞, 食物处理)
snake.move()
# 如果蛇头与食物位置相同 => 吃到食物
if snake.body[0] == food.position:
score += 1
snake.grow = True
food.position = food.random_pos()
# 检测蛇是否撞墙或撞自己
if snake.check_collision():
running = False
# 3) 绘制游戏界面
screen.fill(BLACK) # 清屏(背景黑色)
snake.draw()
food.draw()
draw_text(f"Score: {score}", WHITE, 10, 10)
pygame.display.flip()
# 如果跳出主循环,说明游戏结束
game_over(screen, score)
def game_over(surface, score):
"""
游戏结束界面,可在此添加重来或退出选项
"""
surface.fill(GRAY)
draw_text("Game Over!", WHITE, SCREEN_WIDTH // 2 - 60, SCREEN_HEIGHT // 2 - 30)
draw_text(f"Your Score: {score}", WHITE, SCREEN_WIDTH // 2 - 70, SCREEN_HEIGHT // 2 + 10)
pygame.display.flip()
# 等待若干秒后退出
pygame.time.wait(3000)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
核心逻辑解析
- Snake 类
- 用一个列表
body
存储从头到尾的网格坐标。 - move()
函数在前面插入新的头部坐标,如不需要增长则移除尾部。 - check_collision()
判断是否超出网格边界或头部与身体其他部分重合。
- Food 类
- 只需保存一个
position
表示食物在网格的坐标。 - 当被吃到时,用
random_pos()
重新生成新的位置。
- 主循环
- 通过
clock.tick(FPS)
控制蛇每秒移动多少次。 - 监听方向键来改变蛇的方向。
- 判断蛇头和食物是否重合,若重合则得分、食物重生、蛇变长。
- 若蛇撞墙或撞自己,则游戏结束并跳转到
game_over
界面。
实现效果
总结
通过这篇文章,我们用Python+Pygame从零实现了一款简单的贪吃蛇游戏。该示例涵盖了网格移动、随机食物生成、碰撞检测、方向控制等基本概念,为你打下初步的游戏开发基础。
热门推荐
美式复古家居设计全解析:从色彩搭配到细节打造,教你轻松营造经典温馨家居
厨房里的降糖降压神器:每天喝10毫升醋,血糖可降20%
扫描电子显微镜怎么选?台式扫描电镜与落地式扫描电镜的对比
如何查找Web网址:15种实用方法全攻略
专家解答:如何改善干眼症引起的眼皮发黑
深入解读霍夫变换:从直线检测到圆形检测的图像处理技术【原理、实现与扩展应用】
喝水常呛咳?营养师教你这一招,高龄者重拾饮水自由、安全补水
合同提前终止条款怎么写
石油为什么重要?石油市场的发展趋势如何?
微信上解除合同的效力及注意事项
19朵粉色玫瑰的深层含义:从浪漫到友谊的多重寓意
全部花的花语和象征意义,了解花语,传递心意
拥有花呗是否意味着不再是征信白户?关键看这两个因素
熔断保险丝:电路安全的忠诚卫士
通告撰写指南:定义、类型与技巧
消灭“灰氢”,从减少源头碳排放做起
别让迷雾阻挡你的眼睛,老年性白内障面面观
如何修改论文以回应评审的建议?
肺癌术后发现新增结节、结节增大,要不要那么慌?
最能降血压的运动竟然是它,每周3次就行,随时随地都能做
耳石复位最新研究进展与应用概述
突发眩晕?当心是“耳石症”在捣鬼
移动语音资费标准:国内、漫游及可视电话收费一览
房贷利息抵扣个税全攻略:办理步骤、条件要求及注意事项
新驱动让国产显卡性能暴增120%
出生时没接种卡介苗,怎么补种
认识氮氧化物(NOX)
蒲剧《陈三两》艺惊梨园
养老保险实缴缴费基数解析:了解基础知识
电镀锡:让金属表面焕发新生的技术揭秘