Python Pong游戏开发遇阻:无法解决Paddle碰撞相关报错
解决你的Pong游戏报错问题
首先看你遇到的核心报错:
AttributeError: Ball instance has no attribute 'Paddle'
这个问题的根源很直接——你的Ball类初始化时接收了paddle参数,但没有把它保存为实例属性,导致在hit_paddle方法里尝试访问self.Paddle时找不到这个属性。接下来我会一步步帮你修复这个问题,同时顺便解决代码里的其他潜在错误:
1. 修复Ball类的属性赋值
在Ball的__init__方法里,把传入的paddle参数保存为实例属性:
def __init__(self, canvas, paddle): self.ball = canvas.create_oval(0, 0, SIZE, SIZE, fill='black') self.label = Label(root, text = 'score: {}') self.speedx = 6 self.speedy = 6 self.hit_top = False self.active = True self.canvas = canvas self.paddle = paddle # 新增这一行,保存paddle实例 self.move_active()
然后修改hit_paddle方法里的引用,改成符合Python命名规范的小写开头变量:
def hit_paddle(self, pos): paddle_pos = self.canvas.coords(self.paddle.pad) # 这里把self.Paddle改成self.paddle if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]: if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]: return True return False
2. 修复Paddle类的冗余逻辑
你的Paddle类里的move_active方法完全没必要——因为 paddle 的移动是通过鼠标事件绑定触发的,手动循环调用反而会因为缺少event参数报错。直接删掉这部分冗余代码:
class Paddle: def __init__(self, canvas): self.pad = canvas.create_rectangle(0,0,100,10, fill='red') canvas.bind('<Motion>', self.motion) self.active = True # 删掉self.move_active这一行 def motion(self, event): '''update paddle coordinates using current mouse position''' # 把paddle移到屏幕底部,更符合Pong游戏逻辑 canvas.coords(self.pad, event.x-50, HEIGHT-20, event.x+50, HEIGHT-10)
3. 修复主循环的错误
主循环里有几个拼写和属性访问错误:
ball_canv.self.hit_top应该是ball_canv.hit_toppadddle_canv是拼写错误,应该是paddle_canv- 不需要手动调用
paddle_canv.motion(),鼠标事件已经会自动触发
调整后的主循环:
paddle_canv = Paddle(canvas) ball_canv = Ball(canvas, paddle_canv) while not ball_canv.hit_top: root.update_idletasks() root.update() time.sleep(0.01) root.mainloop()
4. 优化Ball的边界判断逻辑
原来的ball_update方法里边界判断逻辑有问题,比如把底部反弹的条件写反了,我帮你调整成更合理的逻辑:
def ball_update(self): self.canvas.move(self.ball, self.speedx, self.speedy) pos = self.canvas.coords(self.ball) # 碰到左/右边界反弹 if pos[0] <= 0 or pos[2] >= WIDTH: self.speedx = -self.speedx # 碰到顶部,标记游戏结束 if pos[1] <= 0: self.hit_top = True # 碰到底部反弹 if pos[3] >= HEIGHT: self.speedy = -self.speedy # 碰到paddle反弹,确保向上飞 if self.hit_paddle(pos): self.speedy = -abs(self.speedy) self.speedx = random.randrange(-6,6)
完整修正后的代码
from Tkinter import * import time import random HEIGHT = 500 WIDTH = 800 COLOR = 'blue' SIZE = 50 root = Tk() canvas = Canvas(root, width=WIDTH, height=HEIGHT, bg=COLOR) canvas.pack() class Ball: def __init__(self, canvas, paddle): self.ball = canvas.create_oval(0, 0, SIZE, SIZE, fill='black') self.label = Label(root, text='score: 0') self.label.pack() self.speedx = 6 self.speedy = 6 self.hit_top = False self.active = True self.canvas = canvas self.paddle = paddle # 保存paddle实例 self.move_active() def ball_update(self): self.canvas.move(self.ball, self.speedx, self.speedy) pos = self.canvas.coords(self.ball) # 左右边界反弹 if pos[0] <= 0 or pos[2] >= WIDTH: self.speedx = -self.speedx # 碰到顶部,游戏结束 if pos[1] <= 0: self.hit_top = True # 碰到底部反弹 if pos[3] >= HEIGHT: self.speedy = -self.speedy # 碰到paddle反弹 if self.hit_paddle(pos): self.speedy = -abs(self.speedy) self.speedx = random.randrange(-6,6) def hit_paddle(self, pos): paddle_pos = self.canvas.coords(self.paddle.pad) if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]: if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]: return True return False def move_active(self): if self.active and not self.hit_top: self.ball_update() root.after(10, self.move_active) # 调整间隔为10ms,游戏更流畅 class Paddle: def __init__(self, canvas): self.pad = canvas.create_rectangle(0,0,100,10, fill='red') canvas.bind('<Motion>', self.motion) self.canvas = canvas # 保存canvas实例 def motion(self, event): '''update paddle coordinates using current mouse position''' # 限制paddle不超出左右边界 x_center = event.x if x_center -50 < 0: x_center = 50 elif x_center +50 > WIDTH: x_center = WIDTH -50 self.canvas.coords(self.pad, x_center-50, HEIGHT-20, x_center+50, HEIGHT-10) paddle_canv = Paddle(canvas) ball_canv = Ball(canvas, paddle_canv) root.mainloop()
这样修改后,你的游戏应该能正常运行:paddle可以跟随鼠标移动,球碰到边界和paddle都会正确反弹,碰到顶部后游戏结束。
内容的提问来源于stack exchange,提问作者Payton Bandy
相关产品推荐
相关产品推荐

