You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:33:22