Python Turtle迷宫游戏如何无需逐个定义坐标实现墙体碰撞检测
解决方案
你可以用轴对齐矩形碰撞检测的方案实现高效的碰撞校验,全程只用到turtle自带的坐标计算,不需要引入额外库,核心逻辑是预先把所有墙体存成「矩形边界列表」,每次移动前预判位置是否撞墙,具体实现如下:
第一步:定义墙体矩形数据结构
你画的所有墙体都是轴对齐的矩形,每个矩形只需要存4个值:左边界x坐标、右边界x坐标、下边界y坐标、上边界y坐标,把所有墙体的这四个值都存在一个列表里就行,不需要再单独给每个墙体写判断逻辑。
第二步:实现碰撞检测函数
写一个通用的碰撞检测函数,输入海龟的下一个位置坐标,遍历所有墙体矩形,判断坐标是否落在任意一个矩形内部即可。
- 碰撞判断逻辑:如果海龟的x在墙体左、右边界之间,且y在墙体下、上边界之间,就判定为碰撞
第三步:修改移动逻辑
原来的travel函数直接前进,现在改成先计算下一个位置,判断不撞墙再前进,撞墙就停在原地。
可直接运行的修改后代码
import turtle import random screen = turtle.Screen() screen.tracer(0) # ---------------------- 新增:墙体边界列表,所有墙体的矩形边界都存在这里 ---------------------- # 每个元素格式:(左边界x, 右边界x, 下边界y, 上边界y) walls = [ # 中间竖条上下两段 (-20, 20, 140, 200), (-20, 20, -200, -140), # 左上角墙体 (-200, -180, -200, -160), (-200, -180, -160, 200), # 右侧大墙体 (20, 200, -200, 200), (20, 80, 140, 200), (80, 180, 180, 200), (100, 180, -80, 180), (20, 100, -140, -80), # 上侧小墙体 (-80, -60, 140, 160), (-60, -20, 120, 140), (-20, 40, 100, 120), (120, 140, 100, 140), # 中部偏右墙体 (80, 140, 60, 100), (100, 140, 20, 60), (20, 80, 60, 100), # 中部竖条墙体 (20, 20, -100, 60), (-20, 20, -100, -40), (-60, -20, -100, -40), # 左下角墙体 (-140, -60, -160, -140), (-160, -140, -120, -160), (-160, -160, -40, -120), # 中部偏左墙体 (-60, -20, 0, -60), (-20, -20, 0, 40), (-60, -20, 40, 80), (-120, -60, 80, 80), (-120, -120, 80, 200), # 左侧竖条墙体 (-160, -160, 40, 160), (-160, -40, 40, 40), # 右下墙体 (60, 60, -80, 20), (60, 140, -40, -20), # 左侧墙体 (-200, -120, 0, 0), (-120, -100, 0, -80), (-100, -100, -80, -120), (-20, -20, -200, -140) ] # 海龟碰撞判定的容差,因为海龟本身有大小,避免半个身子穿进墙 TOLERANCE = 5 # 碰撞检测函数 def is_collision(next_x, next_y): for (x1, x2, y1, y2) in walls: if (x1 - TOLERANCE <= next_x <= x2 + TOLERANCE) and (y1 - TOLERANCE <= next_y <= y2 + TOLERANCE): return True return False # ---------------------- 原有绘制迷宫的逻辑 ---------------------- mazeWidth=150 tr = turtle.Turtle() tr.width(5) tr.speed(0) tr.penup() tr.goto(-mazeWidth,190) def drawMazeSection(color): tr.pencolor("lightblue") tr.penup() tr.goto(-20,200) tr.pendown() tr.goto(20,200) tr.penup() tr.goto(-20,-200) tr.pendown() tr.goto(20,-200) tr.penup() tr.pencolor("black") tr.goto(-200,200) tr.pendown() tr.goto(-200,-160) tr.begin_fill() tr.goto(-180,-160) tr.goto(-180,-200) tr.goto(-200,-200) tr.end_fill() tr.goto(-20,-200) tr.penup() tr.goto(20,-200) tr.pendown() tr.begin_fill() tr.goto(200,-200) tr.goto(200,200) tr.goto(20,200) tr.goto(20,140) tr.goto(80,140) tr.goto(80,180) tr.goto(180,180) tr.goto(180,-80) tr.goto(100,-80) tr.goto(100,-140) tr.goto(20,-140) tr.goto(20,-200) tr.end_fill() tr.penup() tr.goto(20,160) tr.pendown() tr.begin_fill() tr.goto(-80,160) tr.goto(-80,140) tr.goto(-60,140) tr.goto(-60,160) tr.end_fill() tr.goto(-60,120) tr.goto(-20,120) tr.goto(-20,100) tr.goto(40,100) tr.penup() tr.goto(120,140) tr.pendown() tr.begin_fill() tr.goto(140,140) tr.goto(140,100) tr.goto(120,100) tr.goto(120,120) tr.goto(120,140) tr.end_fill() tr.goto(140,100) tr.goto(80,100) tr.goto(80,80) tr.goto(80,60) tr.begin_fill() tr.goto(140,60) tr.goto(140,20) tr.goto(100,20) tr.goto(100,60) tr.end_fill() tr.goto(20,60) tr.goto(20,-100) tr.goto(20,-40) tr.goto(-20,-40) tr.goto(-20,-100) tr.goto(-60,-100) tr.penup() tr.goto(-60,-140) tr.pendown() tr.goto(-60,-160) tr.goto(-140,-160) tr.goto(-140,-120) tr.goto(-160,-120) tr.goto(-160,-40) tr.penup() tr.goto(-60,-60) tr.pendown() tr.goto(-60,0) tr.goto(-20,0) tr.goto(-20,40) tr.goto(-60,40) tr.goto(-60,80) tr.goto(-120,80) tr.goto(-120,200) tr.penup() tr.goto(-160,160) tr.pendown() tr.goto(-160,40) tr.goto(-40,40) tr.penup() tr.goto(60,20) tr.pendown() tr.goto(60,-80) tr.begin_fill() tr.goto(60,-40) tr.goto(140,-40) tr.goto(140,-20) tr.goto(60,-20) tr.end_fill() tr.penup() tr.goto(-200,0) tr.pendown() tr.goto(-100,0) tr.begin_fill() tr.goto(-100,-120) tr.goto(-100,-80) tr.goto(-120,-80) tr.goto(-120,0) tr.end_fill() tr.penup() tr.goto(-20,-140) tr.pendown() tr.goto(-20,-200) for color in ["#FF0000","#0000FF","#00FF00"]: drawMazeSection(color) screen.tracer(1) wn = turtle.Screen() wn.bgcolor('darkgreen') # 初始化玩家海龟 player = turtle.Turtle() player.shape('turtle') player.color("#DB148E") player.penup() player.goto(0,-200) player.left(90) speed = 1.5 # ---------------------- 修改后的移动逻辑,加碰撞检测 ---------------------- def travel(): heading = player.heading() next_x, next_y = player.xcor(), player.ycor() if heading == 0: # 右 next_x += speed elif heading == 90: # 上 next_y += speed elif heading == 180: # 左 next_x -= speed elif heading == 270: # 下 next_y -= speed # 没撞墙才移动 if not is_collision(next_x, next_y): player.goto(next_x, next_y) wn.ontimer(travel, 10) wn.onkey(lambda: player.setheading(90), 'w') wn.onkey(lambda: player.setheading(180), 'a') wn.onkey(lambda: player.setheading(0), 'd') wn.onkey(lambda: player.setheading(270), 's') wn.listen() travel() wn.mainloop()
后续优化建议
- 如果你要修改迷宫的墙体,只需要修改
walls列表里的对应矩形参数即可,不需要改碰撞逻辑 - 可以调整
TOLERANCE参数适配海龟的大小,避免出现卡墙或者穿模的问题
内容的提问来源于stack exchange,提问作者Dane Jacobs
相关产品推荐
相关产品推荐

