2

I'm trying to make a game in kivy and I'm facing an issue. Whenever I click on my "start game" button on my gamescreen it says

line 46, in move_ball
     ball = self.root.ids.ball
   File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__' 

My main.py

from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.image import Image
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.properties import NumericProperty

class HomeScreen(Screen):
    pass

    def play_sound(self):
        sound = SoundLoader.load('button press sound.wav.')
        if sound:
            sound.play()


    sound = SoundLoader.load('Crowd sound effect.wav')
    sound.loop = True
    sound.play()

class GameScreen(Screen):
    pass


class Ball(Image):
    velocity = NumericProperty(0)

    def on_touch_down(self, touch):
        self.source = "icons/ball1.png"
        self.velocity = 275
        super().on_touch_down(touch)

    def on_touch_up(self, touch):
        self.source = "icons/ball1.png"
        super().on_touch_up(touch)

class MainApp(App):
    GRAVITY = 300


    def move_ball(self, time_passed):
        ball = self.root.ids.ball
        ball.y = ball.y + ball.velocity * time_passed
        ball.velocity = ball.velocity - self.GRAVITY * time_passed


    def start_game(self):
        Clock.schedule_interval(self.move_ball, 1/60.)


    def change_screen(self, screen_name):
        # Get the screen manager from the kv file
        screen_manager = self.root.ids['screen_manager']
        screen_manager.current = screen_name


MainApp().run()

homescreen.kv

#:import utils kivy.utils
#:import FadeTransition kivy.uix.screenmanager.FadeTransition


<HomeScreen>:
FloatLayout:
    canvas:
        Color:
            rgb: utils.get_color_from_hex("#39B3F2")
        Rectangle:
            size: self.size
            pos: self.pos
    GridLayout:
        rows: 1
        pos_hint: {"top": 1, "left": 1}
        size_hint: 1, .9
        Image:
            source: "icons/keepyup.png"
    FloatLayout:
        Button:
            font_size: dp(20)
            font_name: 'SackersGothicStd-Medium.otf'
            text: "PLAY"
            color: "gold"
            pos_hint: { "center_x": .5, "center_y": .3}
            size: 80, 55
            size_hint: None, None
            background_normal: ''
            background_color: (57/255.0, 179/255.0, 242/255.0, .15)


            on_press:

            on_release:
                root.play_sound()
                root.manager.transition = FadeTransition()
                app.change_screen("game_screen")

gamescreen.kv

#:import utils kivy.utils


<GameScreen>:
FloatLayout:
    canvas:
        Color:
            rgb: utils.get_color_from_hex("#39B3F2")
        Rectangle:
            size: self.size
            pos: self.pos
    GridLayout:
        rows: 1
        pos_hint: {"top": 1, "left": 1}
        size_hint: 1, .1
        Image:
            source: "icons/sun.png"
    GridLayout:
        rows: 1
        pos_hint: {"top": 1, "left": 1}
        size_hint: 1, .2
        Image:
            source: "icons/clouds.png"
    GridLayout:
        rows: 1
        pos_hint: {"bottom": 1, "left": 1}
        size_hint: 1, .5
        Image:
            source: "icons/Field4.png"
            allow_stretch: True
            keep_ratio: False
            pos: self.pos

    Button:
        text: "Start game"
        size_hint: None, None
        on_release:
            app.start_game()

    Ball:
        source: "icons/ball1.png"
        size_hint: None, None
        size: 100, 100
        pos: 20, (root.height - 90) / 2.0
        id: ball

main.kv

#:include kv/homescreen.kv
#:include kv/gamescreen.kv


GridLayout:
cols: 1
ScreenManager:
    id: screen_manager
    HomeScreen:
        name: "home_screen"
        id: home_screen
    GameScreen:
        name: "game_screen"
        id: game_screen

I made another kivy project and tried the same thing without the screens and it doesn't show any errors! here's my code

My main.py

from kivy.app import App
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.properties import NumericProperty



class Ball(Image):
    velocity = NumericProperty(0)

    def on_touch_down(self, touch):
        self.source = "ball1.png"
        self.velocity = 275
        super().on_touch_down(touch)

    def on_touch_up(self, touch):
        self.source = "ball1.png"
        super().on_touch_up(touch)


class MainApp(App):
    GRAVITY = 300


    def move_ball(self, time_passed):
        ball = self.root.ids.ball
        ball.y = ball.y + ball.velocity * time_passed
        ball.velocity = ball.velocity - self.GRAVITY * time_passed


    def start_game(self):
        Clock.schedule_interval(self.move_ball, 1/60.)


MainApp().run()

main.kv

#:import utils kivy.utils

FloatLayout:
canvas:
    Color:
        rgb: utils.get_color_from_hex("#39B3F2")
    Rectangle:
        size: self.size
        pos: self.pos
GridLayout:
    rows: 1
    pos_hint: {"top": 1, "left": 1}
    size_hint: 1, .1
    Image:
        source: "sun.png"
GridLayout:
    rows: 1
    pos_hint: {"top": 1, "left": 1}
    size_hint: 1, .2
    Image:
        source: "clouds.png"
GridLayout:
    rows: 1
    pos_hint: {"bottom": 1, "left": 1}
    size_hint: 1, .5
    Image:
        source: "Field4.png"
        allow_stretch: True
        keep_ratio: False
        pos: self.pos

Button:
    text: "Start game"
    size_hint: None, None
    on_release:
        app.start_game()

Ball:
    source: "ball1.png"
    size_hint: None, None
    size: 100, 100
    pos: 20, (root.height - 90) / 2.0
    id: ball

What's wrong with my first project code? because my second one seems to work without getting any errors.

furas
  • 134,197
  • 12
  • 106
  • 148
Tan
  • 43
  • 2
  • 6
  • 1
    always put full error message (starting at word "Traceback") in question (not in comments) as text (not screenshot, not link to external portal). There are other useful information. – furas Nov 23 '21 at 06:18
  • some of your code has wrong indentations. Always put code with correct indentations because if you put wrong indentations then question is only waste of time. Stackoverflow has special function to format code and keep original indentations. – furas Nov 23 '21 at 06:24
  • error shows you in which line you have problem - so first you could use `print()` `print(type())`, etc. to check what you have in variables. It is called `"print debuging"`. – furas Nov 23 '21 at 06:26
  • I'm not sure if it should be `self.root.ids` or `self.ids` - some classes need with `root`, other need without `root`. – furas Nov 23 '21 at 06:27

1 Answers1

4

Although the traceback isn't fully shown in this question, this should be what it looks like at the end:

   File "C:\Users\weebi\Desktop\TestingZone\test1\kv\homescreen.kv", line 37, in <module>
     app.change_screen("game_screen")
   File "C:\Users\weebi\Desktop\TestingZone\test1\main.py", line 53, in change_screen
     screen_manager = self.root.ids.screen_manager
   File "kivy\properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

The reason for the AttributeError: 'super' object has no attribute '__getattr__' exception usually has to do with a non-existence id in a .ids list. Here's a better version of your change_screen method that works as intended:

def change_screen(self, screen_name):
    self.root.current = screen_name

Also fixed your main.kv so that it switches between screens properly

#:include kv/homescreen.kv
#:include kv/gamescreen.kv


ScreenManager:
    id: screen_manager
    HomeScreen:
        name: "home_screen"
        id: home_screen
    GameScreen:
        name: "game_screen"
        id: game_screen

By the way, while this isn't necessarily related to the question, before trying your code, I noticed this line:

ball = self.root.ids.ball

I went ahead and checked the main.kv file and to my surprise, there's no root widget with the id of ball but there's one in the game_screen object, so my OCD acted up and I fixed it for you:

def move_ball(self, time_passed):
    ball = self.root.ids.game_screen.ids.ball
    ball.y = ball.y + ball.velocity * time_passed
    ball.velocity = ball.velocity - self.GRAVITY * time_passed
Weebify
  • 561
  • 4
  • 13
  • It worked! Thank you so much! I would like to thank you for taking your time and helping me with this! – Tan Nov 23 '21 at 23:20
  • One more question! is there any way I can make the ball image be in the center of my screen because currently it's on the left side of my screen? – Tan Nov 23 '21 at 23:23
  • Add this line in your `ball` object: `pos_hint: {"center_x": 0.5}` – Weebify Nov 24 '21 at 04:50
  • it worked! Thank You so much! If I need anything help I'll @ you! – Tan Nov 25 '21 at 00:27
  • No big deal, but I would recommend posting a new question if you encounter any problem that you can't solve instead of asking me, since I'm not that much of a professional – Weebify Nov 25 '21 at 23:03
  • I have a new problem. If you can't solve it it's fine I'll just ask a new question, but I want to make it so that whenever I click on the ball image it goes up in the air, If I click anywhere else it shouldn't do anything. Can you help? I'm talking about this! – Tan Nov 25 '21 at 23:34
  • class Ball(Image): velocity = NumericProperty(0) def on_touch_down(self, touch): self.source = "icons/ball1.png" self.velocity = 275 super().on_touch_down(touch) def on_touch_up(self, touch): self.source = "icons/ball1.png" super().on_touch_up(touch) – Tan Nov 25 '21 at 23:34