Skip to content
Home » Kivy Part 48 – Slugrace – The Game Class

Kivy Part 48 – Slugrace – The Game Class

Spread the love

Hey guys, in this part of the Kivy series we’re going to implement the Game class. This is the class where most of the game’s logic will sit. But before we start, here’s some info for you.

*****

Book Info

I just published my Kivy book, GUI Programming with Python and Kivy. It’s pretty long (over 800 pages) and comprehensive. And, which also counts, easy to read. The book contains lots of illustrations.

This book covers all the basics that you need to know to start programming GUI applications with Python and Kivy. Throughout the book we are building a GUI application from scratch, a fully functional game using all kinds of tools that Kivy has to offer. It’s our Slugrace project, but covered in a much more in-depth manner.

Each part of the book starts with a theoretical introduction of a topic or idea that we then implement in the project. I assume you have no prior knowledge of the Kivy library, but you should have at least some basic knowledge of the Python programming language, including the object-oriented programming paradigm as this is what we will be using a lot in this book.

The book covers all the basic elements of Kivy that you have to know, like widgets, layouts, Kivy ids and properties, graphics, screens, animation, sound. Finally we’ll deploy the app to Windows. It is pretty comprehensive and after you finish it, I’m sure you’ll be able to create your own awesome GUI apps of any kind, not just games.

I hope you will have at least as much fun reading the book as I had writing it.

As far as this Kivy series is concerned, the following parts will contain the most important elements covered in the book. However, some elements will be presented in a simplified way here on my blog or omitted completely.

____________

If you are interested, you can purchase the book in four versions. Here are the links:

1) ebook – pdf version on my website – in full color

Here you can see the description of the book, sample graphics from the book and the full table of contents.

2) ebook – Kindle version on Amazon – in full color

3) paperback version on Amazon – in black and white

4) paperback version on Amazon – in full color

*****

And Now Let’s Move On…

We already created all the screens that our app will be using. In the previous part of the series we added two classes, Slug and Player. We will need the classes to create four slug objects and four player objects.

In our game there will always be four slugs. They will even have names: Speedster, Trusty, Iffy and Slowpoke. Regardless of any settings, there will always be all four.

As far as players are concerned, there may be one, two, three or four players, depending on what we choose in the Settings screen. However, to keep things simple, in our implementation there will always be four instances of the Player class, but if there are fewer players than four, not all of them will be used. Naturally, there are other ways of implementing it, but I decided to do it like that.

Now, the problem is that we need access to the slugs and players in multiple screens. There are widgets that need slug and player info in more than one place, so it would be reasonable to find a place where this info can be stored and can be accessed from any screen. For example player info must be available in the Settings screen, where the names and initial money of each player are set, in the Race screen in the Players’ Stats area, as well as in the Bets screen, Results screen or in the Game Over screen.

So, where are we going to put shared data? There are two major options. We can put the data in the SlugraceApp class. Then we will be able to access it from anywhere in the app. The second option is to put all the shared data in the root widget of our application, so in the class that is returned by the build method of the SlugraceApp class. We’ll be using both approaches to some extent, but the data and slug info will be stored in the root widget class, which is SlugraceScreenManager.

Let’s have a look at the SlugraceScreenManager class again. In the Python file we only have the declaration:

# File name: main.py

...

class SlugraceScreenManager(ScreenManager):
    pass

class SlugraceApp(App):
    def build(self):
        return SlugraceScreenManager()    

if __name__ == '__main__':
    ...

The definition of the class is now completely in the kv file:

# File name: slugrace.kv

<SlugraceScreenManager>: 
    SettingsScreen:
        name: 'settingsscreen'
    RaceScreen:
        name: 'racescreen'
    GameoverScreen:
        name: 'gameoverscreen'

Your Panda3D Magazine

Make Awesome Games and Other 3D Apps

with Panda3D and Blender using Python.

Cool stuff, easy to follow articles.

Get the magazine here (PDF).

Now, as mentioned before, there will be four players and four slugs in the game. Let’s start with the former. In order to create an instance of the Player class, we need to import the Player class to the main.py file first. Then, inside the SlugraceScreenManager class, we will create the objects:

# File name: main.py

...

# We need the Player class to instantiate the four players.
from player import Player

...

class SlugraceScreenManager(ScreenManager):
    # Now let's instantiate the four players.
    player1 = Player()
    player2 = Player()
    player3 = Player()
    player4 = Player()

class SlugraceApp(App):
    ...

We instantiated the four players and are ready to use them now. How about the slugs? Well, we actually defined the four slugs in the Race screen already. Have a look:

# File name: race.kv
#:import race race

...

<RaceScreen>:
    ...
                                    
        ### THE TRACK ###
        ...

            # track 
            ...
                

                # the slugs
                # Speedster
                Slug:
                    body_image: 'speedsterBody'
                    eye_image: 'speedsterEye'
                    y_position: .875                
                
                # Trusty
                Slug:
                    body_image: 'trustyBody'
                    eye_image: 'trustyEye'
                    y_position: .625

                # Iffy
                Slug:
                    body_image: 'iffyBody'
                    eye_image: 'iffyEye'
                    y_position: .375

                # Slowpoke
                Slug:
                    body_image: 'slowpokeBody'
                    eye_image: 'slowpokeEye'
                    y_position: .125
                    
            # winner
            ...

So, as you can see, the four slugs are there. We just need to tell the SlugraceScreenManager class how to access them. This shouldn’t be difficult. The slugs are defined in the Race screen, so we can use properties in the RaceScreen class to access the slugs. As we look at the implementation of the SlugraceScreenManager class in kv, we can easily access the Race screen by an id. So, indirectly we can access the four slugs in the SlugraceScreenManager class too.

Python Jumpstart Course

Learn the basics of Python, including OOP.

with lots of exercises, easy to follow

The course is available on Udemy.

Let’s start by adding the properties in the RaceScreen class:

# File name: race.kv
#:import race race

...

<RaceScreen>:
    canvas:
        ...

    # We'll access the four slugs by ids. To this end let's define 
    # four object properties.
    speedster: _speedster
    trusty: _trusty
    iffy: _iffy
    slowpoke: _slowpoke

    BoxLayout:
        ...
                                    
        ### THE TRACK ###
        ...

            # track 
            ...
                

                # the slugs
                # Speedster
                Slug:
                    id: _speedster
                    body_image: 'speedsterBody'
                    eye_image: 'speedsterEye'
                    y_position: .875                
                
                # Trusty
                Slug:
                    id: _trusty
                    body_image: 'trustyBody'
                    eye_image: 'trustyEye'
                    y_position: .625

                # Iffy
                Slug:
                    id: _iffy
                    body_image: 'iffyBody'
                    eye_image: 'iffyEye'
                    y_position: .375

                # Slowpoke
                Slug:
                    id: _slowpoke
                    body_image: 'slowpokeBody'
                    eye_image: 'slowpokeEye'
                    y_position: .125
                    
            # winner
            ...

Now we need to modify the SlugraceScreenManager class so that it has access to the slugs:

# File name: slugrace.kv

<SlugraceScreenManager>: 
    # Here are the properties on the root widget class that we
    # will use to access the slugs from outside the Race screen.
    speedster: _racescreen.speedster
    trusty: _racescreen.trusty
    iffy: _racescreen.iffy
    slowpoke: _racescreen.slowpoke

    SettingsScreen:
        name: 'settingsscreen'
    RaceScreen:
        # Let's add the id to be able to access the Race screen.
        id: _racescreen
        name: 'racescreen'
    GameoverScreen:
        name: 'gameoverscreen'

Now, one more thing before we continue. This is not necessary, but as the SlugraceScreenManager class is going to contain all the game data, like the players, the slugs, but also all sorts of other stuff that we are going to add to it in the following parts of the series, let’s rename it Game. Here’s the Python file:

# File name: main.py

...

class Game(ScreenManager):
    player1 = Player()
    player2 = Player()
    player3 = Player()
    player4 = Player()

class SlugraceApp(App):
    def build(self):
        return Game()    

if __name__ == '__main__':
    ...

And here’s the kv file:

# File name: slugrace.kv

<Game>: 
    speedster: _racescreen.speedster
    trusty: _racescreen.trusty
    iffy: _racescreen.iffy
    slowpoke: _racescreen.slowpoke

    SettingsScreen:
        name: 'settingsscreen'
    RaceScreen:
        id: _racescreen
        name: 'racescreen'
    GameoverScreen:
        name: 'gameoverscreen'

Now, the last thing to do is make sure all screens have access to the Game class because they will need player info, slug info and other data defined in it. In case of the Settings, Race and Game Over screens, it’s very easy because you can use the manager property to access the Game class (which is the three classes’ screen manager after all). As far as the Bets and Results screens are concerned, it’s a bit more complicated, but if you look at how their screen manager is embedded in the Race screen and use the parent and manager properties, you will quickly figure it out.

Blender Jumpstart Course

Learn the basics of 3D modeling in Blender.

step-by-step, easy to follow, visually rich

The course is available on Udemy and on Skillshare.

For consistency, let’s add a game property to each of the screens and set it to the Game class. Here’s how you should do it in the Settings screen. Just add the following line of code below the canvas instructions in the SettingsScreen rule:

# File name: settings.kv
#:import settings settings

...

<SettingsScreen>:
    canvas:
        ...

    game: root.manager

    BoxLayout:
        ...

Here root refers to the root widget, which is SettingsScreen, and manager is its screen manager, so the Game class.

Here’s the Race screen, which is very similar:

# File name: race.kv
#:import race race

...

<RaceScreen>:
    canvas:
        ...

    game: root.manager
    
    speedster: _speedster
    trusty: _trusty
    iffy: _iffy
    slowpoke: _slowpoke

    BoxLayout:
        ...

And here’s the Game Over screen, which is also very similar:

# File name: gameover.kv
#:import gameover gameover

<GameoverScreen>: 
    canvas:
        ...

    game: root.manager

    BoxLayout:
        ...

And now let’s have a look at how the Bets and Results screens are embedded in the Race screen. Or rather their screen manager:

# File name: race.kv
#:import race race

...

<RaceScreen>:
    ...

    BoxLayout:
        ...   
        
        ### THE BETS ###  
        BoxLayout:
            ...

            RaceScreenManager:

What we want to do is get access to the RaceScreen class and next to its manager. As you can see in the simplified hierarchy above, RaceScreen is RaceScreenManager’s parent’s parent’s parent. Keeping that in mind, we can access the Game class from the Bets screen like so:

# File name: bets.kv
#:import bets bets

...

<BetsScreen>:
    canvas:
        ...

    game: root.manager.parent.parent.parent.manager

    BoxLayout:
        ...

Here’s a visualization that will make things clearer to you:

game class

Similarly, in the Results screen we’ll have:

# File name: results.kv
#:import results results
            
...

<ResultsScreen>: 
    canvas:
        ...

    game: root.manager.parent.parent.parent.manager

    BoxLayout:                     
        ...

Now we can access the Game class from any screen using the game property.


Spread the love

Leave a Reply