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.
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