Python turtle开发Pong游戏paddle_a碰撞失效及关窗报错问题
Turtle版Pong游戏异常修复方案
问题1:左侧球拍paddle_a碰撞检测不生效
根因
x轴判断条件写反,条件对应的数值区间不存在,导致if语句永远不会触发:
右侧球拍paddle_b在x正半轴350坐标位置,碰撞判断用ball.xcor() > 340 and ball.xcor() < 350是成立的——小球从左向右移动时,会进入340到350的碰撞区间。
但左侧球拍paddle_a在x负半轴-350坐标位置,原代码写的ball.xcor() > -340 and ball.xcor() < -350是不可能满足的:负数比较时-350 < -340,没有数字能同时大于-340又小于-350,所以碰撞逻辑永远不会执行。
修复方法
- 找到paddle_a对应的碰撞判断if语句,把x轴条件的大小判断调换,匹配-350到-340的有效碰撞区间即可,修正后的代码段如下:
if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50): ball.setx(-340) ball.dx *= -1
问题2:关闭窗口抛出tkinter.TclError: invalid command name ".!canvas"异常
根因
代码用了无退出条件的while True死循环驱动动画,点击窗口关闭按钮时,tkinter的画布canvas资源会先被系统销毁,但后台循环还在运行,继续执行ball.setx()这类操作画布元素的指令时,找不到已销毁的画布组件就会抛出该错误。
修复方法
- 新增全局
running状态标记,初始值设为True - 编写窗口关闭回调函数,触发关闭时先将
running设为False,再执行窗口销毁逻辑 - 给主窗口绑定关闭事件到上述回调函数
- 主循环增加
running状态判断,状态为False时立刻退出循环,不再操作已销毁的画布元素
完整修复后可运行代码
import turtle # 运行状态标记 running = True def on_close(): global running running = False window.bye() window = turtle.Screen() window.title("Pong but cool") window.bgcolor("black") window.setup(width=800,height=600) window.tracer(0) # 绑定窗口关闭事件 window.getcanvas().winfo_toplevel().protocol("WM_DELETE_WINDOW", on_close) # 球拍 paddle_a = turtle.Turtle() paddle_a.speed(0) paddle_a.shape("square") paddle_a.color("white") paddle_a.shapesize(stretch_wid=5, stretch_len=1) paddle_a.penup() paddle_a.goto(-350, 0) paddle_b = turtle.Turtle() paddle_b.speed(0) paddle_b.shape("square") paddle_b.color("white") paddle_b.shapesize(stretch_wid=5, stretch_len=1) paddle_b.penup() paddle_b.goto(350, 0) # 小球 ball = turtle.Turtle() ball.speed(0) ball.shape("square") ball.color("white") ball.penup() ball.goto(0, 0) ball.dx = 0.05 ball.dy = 0.05 # 按键控制函数 def paddle_a_up(): y = paddle_a.ycor() y += 20 paddle_a.sety(y) def paddle_a_down(): y = paddle_a.ycor() y -= 20 paddle_a.sety(y) def paddle_b_up(): y = paddle_b.ycor() y += 20 paddle_b.sety(y) def paddle_b_down(): y = paddle_b.ycor() y -= 20 paddle_b.sety(y) # 键盘绑定 window.listen() window.onkeypress(paddle_a_up, "w") window.onkeypress(paddle_a_down, "s") window.onkeypress(paddle_b_up, "Up") window.onkeypress(paddle_b_down, "Down") # 主循环增加运行状态判断 while running: window.update() # 小球移动 ball.setx(ball.xcor() + ball.dx) ball.sety(ball.ycor() + ball.dy) # 边界检测 if ball.ycor() > 290: ball.sety(290) ball.dy *= -1 if ball.ycor() < -290: ball.sety(-290) ball.dy *= -1 if ball.xcor() > 390: ball.goto(0, 0) ball.dx *= -1 if ball.xcor() < -390: ball.goto(0, 0) ball.dx *= -1 # 碰撞检测 if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50): ball.setx(340) ball.dx *= -1 # 修复后的左侧球拍碰撞逻辑 if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50): ball.setx(-340) ball.dx *= -1
内容的提问来源于stack exchange,提问作者Anslip
相关产品推荐
相关产品推荐

