Matt
Matt

Reputation: 173

kivy official pong tutorial: 'NoneType' object has no attribute 'center'

I'm trying to learn Kivy with this tutorial. I've copy pasted the code after "Here is the entire code for this step:" to main.py and main.kv as described. When trying to run, I'm getting:

Traceback (most recent call last):
  File "main.py", line 47, in <module>
   PongApp().run()
  File "/home/kivy/code/kivy/kivy/app.py", line 527, in run
   root = self.build()
  File "main.py", line 41, in build
   game.serve_ball()
  File "main.py", line 23, in serve_ball
   self.ball.center = self.center
AttributeError: 'NoneType' object has no attribute 'center'

What am I doing wrong?

main.kv:

#:kivy 1.0.9

<PongBall>:
    size: 50, 50 
    canvas:
        Ellipse:
            pos: self.pos
            size: self.size          

<PongGame>:
    ball: pong_ball

    canvas:
        Rectangle:
            pos: self.center_x-5, 0
            size: 10, self.height

    Label:
        font_size: 70  
        center_x: root.width / 4
        top: root.top - 50
        text: "0"

    Label:
        font_size: 70  
        center_x: root.width * 3 / 4
        top: root.top - 50
        text: "0"

    PongBall:
        id: pong_ball
        center: self.parent.center

main.py:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty,\
    ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint


class PongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x, velocity_y)

    def move(self):
        self.pos = Vector(*self.velocity) + self.pos


class PongGame(Widget):
    ball = ObjectProperty(None)

    def serve_ball(self):
        self.ball.center = self.center
        self.ball.velocity = Vector(4, 0).rotate(randint(0, 360))

    def update(self, dt):
        self.ball.move()

        #bounce off top and bottom
        if (self.ball.y < 0) or (self.ball.top > self.height):
            self.ball.velocity_y *= -1

        #bounce off left and right
        if (self.ball.x < 0) or (self.ball.right > self.width):
            self.ball.velocity_x *= -1


class PongApp(App):
    def build(self):
        game = PongGame()
        game.serve_ball()
        Clock.schedule_interval(game.update, 1.0 / 60.0)
        return game


if __name__ == '__main__':
    PongApp().run()

Upvotes: 2

Views: 8914

Answers (3)

brousch
brousch

Reputation: 1082

You have the wrong name for your KV file. It should be "pong.kv". If the name of the KV file matches the name of your app (minus App), then it will be automagically used.

You named your KV file "main.kv" which did not match with your app name "PongApp", so the magic did not happen. You were able to manually load the KV file by using Builder.load_file(). If you look back at the tutorial, you can see it requires you to name the KV file as "pong.kv".

Upvotes: 9

Matt
Matt

Reputation: 173

I've added

from kivy.lang import Builder

Builder.load_file('main.kv')

to my main.py and it works perfectly. Why "main.kv" was not detected automatically is still a mistery to me.

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308520

self.ball is being initialized with:

ball = ObjectProperty(None)

This gives it a default value of None. Thus when you try to access self.ball.center it fails.

The tutorial contains a step that you probably missed:

Don’t forget to hook it up in the kv file, by giving the child widget an id and setting the PongGame’s ball ObjectProperty to that id

Upvotes: 1

Related Questions