Search code examples
pythonkivykivy-language

Python kivy updating game score


I'm making a game in kivy and trying to update the game score by 1 whenever the soccer ball is pressed on. I'm facing this issue.

"in on_touch_down self.root.ids.game_screen.ids.label.score.text = str(int(self.root.ids.game_screen.ids.score.text)+1)

AttributeError: 'Ball' object has no attribute 'root' "

This is my code!

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
from kivy.vector import Vector


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

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


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


def on_touch_down(self, touch):
    if Vector(self.center).distance(touch.pos) <= 33:
        self.root.ids.game_screen.ids.label.score.text = str(int(self.root.ids.game_screen.ids.score.text)+1)
        sound = SoundLoader.load('Soccer ball sound.wav')
        sound.play()
        self.source = "icons/ball.png"
        self.velocity = 275
    return super().on_touch_down(touch)


def on_touch_up(self, touch):
    if Vector(self.center).distance(touch.pos) <= 33:
        self.source = "icons/ball.png"
    return super().on_touch_up(touch)


class MainApp(App):
    GRAVITY = 300


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


def start_game(self):
    Clock.schedule_interval(self.move_ball, 1/60.)
    self.root.ids.game_screen.ids.score.text = "0"


def change_screen(self, screen_name):
    self.root.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, .10)


                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

        Label:
            id: score
            size_hint: None, None
            font_size: dp(25)
            font_name: 'SackersGothicStd-Medium.otf'
            text: "0"
            color: "gold"
            pos_hint: { "center_x": 0.1, "center_y": 0.9}

        Button:
            size_hint: None, None
            font_size: dp(20)
            font_name: 'SackersGothicStd-Medium.otf'
            text: "Start Game"
            color: "gold"
            pos_hint: { "center_x": 0.5, "center_y": 0.3}
            size: 150, 55
            size_hint: None, None
            background_normal: ''
            background_color: (57/255.0, 179/255.0, 242/255.0, .10)


            on_release:
                self.disabled = True
                self.opacity = 0
                root.play_sound()
                app.start_game()


        Ball:
            source: "icons/ball.png"
            size_hint: None, None
            size: 500, 500
            pos_hint: {"center_x": 0.5}
            id: ball

main.kv

#: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

Solution

  • Your code:

    self.root.ids.game_screen.ids.label.score.text = str(int(self.root.ids.game_screen.ids.score.text)+1)
    

    is trying to access the root attribute of the Ball object (self.root), but your Ball has no root attribute. So you get the described error.

    You can accomplish what you want by accessing the root attribute of the App. Try replacing the above line with:

            label = App.get_running_app().root.get_screen('game_screen').ids.score
            label.text = str(int(label.text)+1)