AttributeError: 'Ball' object has no attribute 'hit_paddle'

Discussion in 'Python' started by nica1123, Feb 5, 2019.

  1. nica1123

    nica1123

    Joined:
    Feb 5, 2019
    Messages:
    1
    Likes Received:
    0
    Beginner here. I am trying to do the game bounce.
    This is the error message:

    Traceback (most recent call last):
    File "C:\Users\Anthony\AppData\Local\Programs\Python\Python36-32\paddlebounce.py", line 76, in <module>
    ball.draw()
    File "C:\Users\Anthony\AppData\Local\Programs\Python\Python36-32\paddlebounce.py", line 24, in draw
    if self.hit_paddle(pos) == True:
    AttributeError: 'Ball' object has no attribute 'hit_paddle'
    >>>

    Code (Python):
    from tkinter import *
    import random
    import time
    class Ball:
        def __init__(self, canvas, paddle, color):
            self.canvas = canvas
            self.paddle = paddle
            self.id = canvas.create_oval(10, 10, 25, 25, fill=color)
            self.canvas.move(self.id, 245, 100)
            starts = [-3, -2, -1, 1, 2, 3]
            random.shuffle(starts)
            self.x = starts[0]
            self.y = -3
            self.canvas_height = self.canvas.winfo_height()
            self.canvas_width = self.canvas.winfo_width()

        def draw(self):
            self.canvas.move(self.id, self.x, self.y)
            pos = self.canvas.coords(self.id)
            if pos[1] <= 0:
                self.y = 3
            if pos[3] >= self.canvas_height:
                self.y = -3
            if self.hit_paddle(pos) == True:
                self.y = -3
            if pos[0] <= 0:
                self.x = 3
            if pos[2] >= self.canvas_width:
                self.x = -3

    class Paddle:
        def __init__(self, canvas, color):
                self.canvas = canvas
                self.id = canvas.create_rectangle(0, 0, 100, 10, fill=color)
                self.canvas.move(self.id, 200, 300)
                self.x = 0
                self.canvas_width = self.canvas.winfo_width()
                self.canvas.bind_all('<KeyPress-Left>', self.turn_left)
                self.canvas.bind_all('<KeyPress-Right>', self.turn_right)
               
        def hit_paddle(self, pos):
            paddle_pos = self.canvas.coords(self.paddle.id)
            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 draw(self):
            self.canvas.move(self.id, self.x, 0)
            pos = self.canvas.coords(self.id)
            if pos[0] <= 0:
                self.x = 0
            elif pos[2] >= self.canvas_width:
                self.x = 0
         
        def turn_left(self, evt):
            self.x = -2

        def turn_right(self, evt):
            self.x = 2
           
           
    tk = Tk()
    tk.title("Game")
    tk.resizable(0, 0)
    tk.wm_attributes("-topmost", 1)
    canvas =Canvas(tk, width=500, height=400, bd=0, highlightthickness=0)
    canvas.pack()
    tk.update()

    paddle = Paddle(canvas, 'blue')
    ball = Ball(canvas, paddle, 'red')

    while 1:
        ball.draw()
        paddle.draw()
        tk.update_idletasks()
        tk.update()
        time.sleep(0.01)
       
     
    What am I doing wrong? I have been trying to figure it out for over a week.
     
    nica1123, Feb 5, 2019
    #1
    1. Advertisements

  2. nica1123

    JasKinasis

    Joined:
    Jun 27, 2018
    Messages:
    12
    Likes Received:
    5
    Location:
    /dev/null
    I'm a little late to the party here. I haven't visited this site for a while. I hope you've already managed to fix this.
    As there are no replies to this - I'll put in my two cents.....

    There are two lines that I can see which are problematic in your code.

    Your error message quite clearly states that your Ball class does not have a hit_paddle attribute. Which it does not!
    hit_paddle is clearly an attribute of your Paddle class.

    From looking at your code, I can see that your Ball class contains an instance of your Paddle class.
    So the line that you are getting an error message about should be changed from:
    Code (Text):

    if self.hit_paddle(pos)==True:
     
    to:
    Code (Text):

    if self.paddle.hit_paddle(pos):
     
    Note: The "==true" part of the statement is already implicit in the if statement, so it can be left out..... If that makes sense??
    In the context of the line, self refers to an active instance of your Ball class. Your Ball class does not have a hit_paddle attribute, but it's paddle attribute (an instance of Paddle) does. Hence the need to use "self.paddle.hit_paddle(pos)"

    After fixing that problem - the other line that you will get an error message about is inside your hit paddle method itself. Specifically this line:
    Code (Text):

        paddle_pos = self.canvas.coords(self.paddle.id)
     
    The problem in the above line is the "self.paddle.id" part. The Paddle class doesn't have a "paddle" attribute.
    But the Paddle class does have an "id" attribute. So the attribute you are really intending to refer to is "self.id" NOT "self.paddle.id".
    So change that line to:
    Code (Text):

        paddle_pos = self.canvas.coords(self.ids)
     
    And that should fix your code.

    It looks to me like you are experiencing a bit of confusion about what "self" actually refers to.

    The thing to remember is that "self" always refers to an instance of the class you are inside the definition of.
    So inside your Ball class, "self" always refers to an instance of your Ball class. In the Paddle class, "self" refers to an instance of your Paddle class.

    So I think you just need to be a little more mindful of the way your classes are laid out.

    Your Ball class contains an instance of the Paddle class.
    To access the Ball classes methods/attributes from inside the Ball class you would use "self.attribute_name"
    To access the Paddles methods/attributes from inside the Ball class, you would use "self.paddle.attribute_name".
    To access the Paddles methods/attributes from inside the Paddle class, you would use "self.attribute_name".

    Does that all make sense?
     
    JasKinasis, Feb 27, 2019
    #2
    Ian likes this.
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.