我对母亲第一部手机的记忆,总绕不开里面的那款游戏——没错,就是经典的贪吃蛇游戏。它玩法简单,却让人欲罢不能。我还记得在母亲的手机上一遍遍地玩,输了就重新开始,乐此不疲!
在本文中,我们将学习构建一个简易的贪吃蛇游戏,核心会用到Python的turtle模块。请注意:这是一份面向Python初阶到中阶学习者的教程,要求读者熟悉Python基础(如函数、循环、模块导入、条件语句),并对面向对象编程有基础认知(尤其是从类创建对象实例)。为了便于理解,我会逐行解释每一段代码。现在,让我们开始吧!

经典的贪吃蛇游戏规则很简单:
背景简洁,屏幕上随机出现食物
蛇吃到食物后身体变长,分数增加
蛇撞到边界墙或自身时,游戏结束
要在Python中实现这款游戏,我们需要解决以下核心问题:
搭建游戏窗口(经典贪吃蛇的背景是暗黄绿色)
创建蛇的身体(初始为小黑蛇,吃食物后逐渐变长)
控制蛇的移动(通过方向键实现上下左右移动)
生成食物(在屏幕随机位置出现)
检测蛇吃食物(吃到后加分、变长,同时生成新食物)
检测碰撞(撞墙或撞到自身则游戏结束)
接下来我们逐步编码实现。
首先在IDE中新建项目(命名为“Snake Game”),创建“snake game.py”文件。第一步先导入turtle模块的核心类:
from turtle import Screen, Turtle
Turtle是Python内置模块,能通过代码在屏幕上绘制图形、线条、图案并实现动画。它的核心逻辑就像“一只背着画笔的乌龟”:你指挥它移动,它就会在路径上留下轨迹。可以控制乌龟前进、左转指定角度、画圆等,是可视化代码逻辑的绝佳工具,能直观练习变量、循环、函数、坐标和基础动画。
可参考Turtle官方文档了解更多用法。
我们通过Screen类创建游戏窗口,并自定义样式:
# 搭建游戏窗口
screen = Screen()
screen.setup(width=600, height=600) # 设置窗口尺寸600×600
screen.bgcolor("green yellow") # 设置背景色(接近经典游戏的黄绿色)
screen.title("Snake Game") # 设置窗口标题
screen.tracer(0) # 关闭动画追踪(后续手动更新画面)
screen.exiton click() # 点击窗口才关闭(否则会瞬间闪退)
setup():设置窗口宽高
bgcolor():设置背景色(颜色名称可参考配色表)
tracer(0):关闭自动动画刷新,后续通过update()手动控制,避免蛇身体分段创建的动画
exiton click():保证窗口不会执行完代码就立即关闭
运行上述代码,会得到一个600×600的黄绿色窗口。

蛇的身体由多个正方形片段组成,我们用Turtle创建3个正方形片段,拼接成初始蛇身:
# 创建蛇的身体
segments = [] # 存储蛇的所有身体片段
starting_positions = [(0,0), (-20,0), (-40,0)] # 初始三段身体的坐标
# 定义添加蛇身片段的函数(后续吃食物时复用)
def add_segments(position):
new_segment = Turtle("square") # 创建正方形海龟对象
new_segment.color("black") # 设置颜色为黑色
new_segment.penup() # 抬笔(避免移动时留下轨迹)
new_segment.goto(position) # 移动到指定坐标
segments.append(new_segment) # 将片段加入列表
# 初始化蛇身
for position in starting_positions:
add_segments(position)
screen.update() # 手动更新画面,显示蛇身
初始蛇身由3个20×20像素的正方形组成(Turtle默认尺寸)
penup():抬笔状态下移动不会绘制线条
封装add_segments()函数:后续蛇吃食物时,可直接调用该函数添加新片段
若想直观看到分段创建的动画,可导入time模块并在循环中添加time.sleep(1),同时注释掉screen.tracer(0)。

让蛇动起来的核心逻辑:除头部外,每个片段都移动到前一个片段的位置,最后头部向前移动。
import time # 导入时间模块控制移动速度
game_is_on = True # 游戏运行状态标识
while game_is_on:
screen.update() # 每次循环刷新画面
time.sleep(0.1) # 控制移动速度(0.1秒延迟,值越大速度越慢)
# 让身体片段跟随前一个片段移动
for seg_num in range(len(segments)-1, 0, -1):
# 获取前一个片段的坐标
new_x = segments[seg_num - 1].xcor()
new_y = segments[seg_num - 1].ycor()
# 当前片段移动到前一个片段的位置
segments[seg_num].goto(new_x, new_y)
# 蛇头向前移动20像素(一个片段的宽度)
segments[0].forward(20)

倒序遍历蛇身片段(从最后一段到第一段):确保每个片段都跟随前一段移动
xcor()/ycor():获取海龟对象的x/y坐标
forward(20):蛇头向前移动20像素(与片段尺寸一致)
time.sleep(0.1):控制移动帧率,可调整数值改变蛇的速度
运行代码,就能看到蛇持续向前移动。
通过键盘方向键控制蛇的移动方向,同时限制蛇不能180度反向(比如向左走时不能直接向右):
# 控制蛇的移动方向
screen.listen() # 监听键盘输入
def turn_up():
# 向上时不能直接向下(heading=270是向下)
if segments[0].heading() != 270:
segments[0].setheading(90) # 90度=向上
def turn_down():
# 向下时不能直接向上
if segments[0].heading() != 90:
segments[0].setheading(270) # 270度=向下
def turn_left():
# 向左时不能直接向右
if segments[0].heading() != 0:
segments[0].setheading(180) # 180度=向左
def turn_right():
# 向右时不能直接向左
if segments[0].heading() != 180:
segments[0].setheading(0) # 0度=向右
# 绑定方向键与对应函数
screen.onkey(turn_up, "Up")
screen.onkey(turn_down, "Down")
screen.onkey(turn_left, "Left")
screen.onkey(turn_right, "Right")

screen.listen():开启键盘监听
setheading(角度):设置海龟朝向(0=右,90=上,180=左,270=下)
onkey(函数名, 按键名):绑定按键与响应函数
条件判断:避免蛇直接反向移动(符合经典游戏规则)
将这段代码放在游戏循环前,运行后即可通过方向键控制蛇的移动。
创建随机位置的红色圆形食物,尺寸为10×10像素(默认20×20的一半):
# 创建食物
import random
food = Turtle()
food.color("red") # 食物颜色为红色
food.shape("circle") # 食物形状为圆形
food.penup() # 抬笔避免轨迹
food.shapesize(stretch_len=0.5, stretch_wid=0.5) # 缩小为10×10像素
food.speed("fastest") # 最快速度移动(无动画延迟)
# 随机生成食物坐标(限制在-275到275之间,避免靠近边界)
def refresh():
random_x = random.randint(-275, 275)
random_y = random.randint(-275, 275)
food.goto(random_x, random_y)
# 初始化食物位置
refresh()

shapesize(stretch_len=0.5, stretch_wid=0.5):将默认20×20的图形缩小50%
refresh()函数:重新生成随机坐标,蛇吃到食物后调用该函数刷新食物位置
坐标范围限制在-275~275:避免食物出现在边界,导致蛇撞墙才能吃到
当蛇头与食物的距离小于15像素时,判定为“吃到食物”,此时:
刷新食物位置
蛇身增加一段
分数加1
# 蛇身延长函数
def extend():
# 在最后一个片段的位置添加新片段
add_segments(segments[-1].position())
# 游戏主循环(整合之前的移动逻辑)
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
# 蛇身跟随移动
for seg_num in range(len(segments)-1, 0, -1):
new_x = segments[seg_num - 1].xcor()
new_y = segments[seg_num - 1].ycor()
segments[seg_num].goto(new_x, new_y)
segments[0].forward(20)
# 检测吃到食物
if segments[0].distance(food) < 15:
refresh() # 刷新食物位置
extend() # 蛇身延长

distance(food):计算蛇头与食物的直线距离
extend():调用之前的add_segments()函数,在蛇尾添加新片段
判定阈值15:通过测试确定的合理值(避免因坐标精度导致无法判定)
创建计分板,蛇吃到食物后更新分数:
# 初始化计分板
score = 0
# 绘制"Score = "文本
scoreboard = Turtle()
scoreboard.color("black")
scoreboard.penup()
scoreboard.hideturtle() # 隐藏海龟图标,只显示文字
scoreboard.goto(0, 250) # 文本位置(屏幕上方)
scoreboard.write("Score = ", align="center", font=("Arial", 12, "normal"))
# 绘制分数数字
my_score = Turtle()
my_score.color("black")
my_score.penup()
my_score.hideturtle()
my_score.goto(40, 250)
my_score.write(score, align="center", font=("Arial", 12, "normal"))
# 更新游戏循环中的吃食物逻辑
game_is_on = True
while game_is_on:
# (保留之前的移动、跟随逻辑)
# 检测吃到食物
if segments[0].distance(food) < 15:
refresh()
extend()
score += 1 # 分数加1
my_score.clear() # 清空原有分数
my_score.write(score, align="center", font=("Arial", 12, "normal")) # 写入新分数

# 游戏结束提示
def game_over():
game_over_text = Turtle()
game_over_text.color("black")
game_over_text.penup()
game_over_text.hideturtle()
game_over_text.write("GAME OVER", align="center", font=("Arial", 40, "normal"))
当蛇头超出窗口边界(x/y坐标超过±290)时,游戏结束:
game_is_on = True
while game_is_on:
# (保留之前的所有逻辑)
# 检测撞墙
if (segments[0].xcor() > 290 or segments[0].xcor() < -290 or
segments[0].ycor() > 290 or segments[0].ycor() < -290):
game_is_on = False
game_over()
蛇头与身体任意片段的距离小于10像素时,判定为“撞到自身”,游戏结束:
game_is_on = True
while game_is_on:
# (保留之前的所有逻辑)
# 检测撞到自身
for segment in segments[1:]: # 遍历除头部外的所有片段
if segments[0].distance(segment) < 10:
game_is_on = False
game_over()

将所有逻辑整合,最终完整代码如下:
from turtle import Screen, Turtle
import time
import random
# 1. 搭建游戏窗口
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("green yellow")
screen.title("Snake Game")
screen.tracer(0)
# 2. 蛇身相关函数
segments = []
starting_positions = [(0,0), (-20,0), (-40,0)]
def add_segments(position):
new_segment = Turtle("square")
new_segment.color("black")
new_segment.penup()
new_segment.goto(position)
segments.append(new_segment)
# 初始化蛇身
for position in starting_positions:
add_segments(position)
# 蛇身延长
def extend():
add_segments(segments[-1].position())
# 3. 控制蛇的方向
def turn_up():
if segments[0].heading() != 270:
segments[0].setheading(90)
def turn_down():
if segments[0].heading() != 90:
segments[0].setheading(270)
def turn_left():
if segments[0].heading() != 0:
segments[0].setheading(180)
def turn_right():
if segments[0].heading() != 180:
segments[0].setheading(0)
screen.listen()
screen.onkey(turn_up, "Up")
screen.onkey(turn_down, "Down")
screen.onkey(turn_left, "Left")
screen.onkey(turn_right, "Right")
# 4. 创建食物
food = Turtle()
food.color("red")
food.shape("circle")
food.penup()
food.shapesize(stretch_len=0.5, stretch_wid=0.5)
food.speed("fastest")
def refresh():
random_x = random.randint(-275, 275)
random_y = random.randint(-275, 275)
food.goto(random_x, random_y)
refresh()
# 5. 计分板
score = 0
scoreboard = Turtle()
scoreboard.color("black")
scoreboard.penup()
scoreboard.hideturtle()
scoreboard.goto(0, 250)
scoreboard.write("Score = ", align="center", font=("Arial", 12, "normal"))
my_score = Turtle()
my_score.color("black")
my_score.penup()
my_score.hideturtle()
my_score.goto(40, 250)
my_score.write(score, align="center", font=("Arial", 12, "normal"))
# 6. 游戏结束提示
def game_over():
game_over_text = Turtle()
game_over_text.color("black")
game_over_text.penup()
game_over_text.hideturtle()
game_over_text.write("GAME OVER", align="center", font=("Arial", 40, "normal"))
# 7. 游戏主循环
game_is_on = True
while game_is_on:
screen.update()
time.sleep(0.1)
# 蛇身跟随移动
for seg_num in range(len(segments)-1, 0, -1):
new_x = segments[seg_num - 1].xcor()
new_y = segments[seg_num - 1].ycor()
segments[seg_num].goto(new_x, new_y)
segments[0].forward(20)
# 检测吃到食物
if segments[0].distance(food) < 15:
refresh()
extend()
score += 1
my_score.clear()
my_score.write(score, align="center", font=("Arial", 12, "normal"))
# 检测撞墙
if (segments[0].xcor() > 290 or segments[0].xcor() < -290 or
segments[0].ycor() > 290 or segments[0].ycor() < -290):
game_is_on = False
game_over()
# 检测撞到自身
for segment in segments[1:]:
if segments[0].distance(segment) < 10:
game_is_on = False
game_over()
screen.exiton click()
本教程中,我们成功用Python实现了经典的贪吃蛇游戏,核心用到了:
Python基础:函数定义与调用、列表/元组、循环、条件语句
面向对象:从Turtle模块的类创建对象并调用方法
动画控制:通过tracer和update实现流畅的游戏画面
你可以基于此代码进一步优化,比如增加难度(蛇移动速度随分数提升)、添加音效、记录最高分等。如果对代码有任何疑问,或有优化建议,欢迎留言分享!现在,运行代码,玩玩自己制作的贪吃蛇游戏,挑战你的朋友吧!
Turtle核心用法:通过Screen控制窗口,Turtle创建图形/文字,tracer关闭自动动画后用update手动刷新
蛇移动逻辑:倒序遍历身体片段,让每个片段跟随前一个移动,最后移动头部
碰撞检测:通过distance()计算距离,判定吃食物/撞自身,通过坐标范围判定撞墙
扩展性:可通过调整time.sleep()的参数改变蛇速,或增加新功能(如最高分记录、关卡难度)

扫码加好友,拉您进群



收藏
