Skip to content
Home » Kivy Part 51 – Slugrace – Player Settings

Kivy Part 51 – Slugrace – Player Settings

Spread the love

Hey guys, in the previous part of the Kivy series we handled the radio button events in the Settings screen. As mentioned before, the text input events will be handled in a separate part, so let’s now move on to the Ready Button’s on_press event. But before we start, here’s some info for you.

Book Info

I published a 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…

At this moment the on_press event is implemented like so:

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

...

        ### READY BUTTON ###
        RedButton:
            text: 'Ready'
            on_press: root.manager.current = 'racescreen'

So, it just switches to another screen. By the way, now root.manager and root.game reference the same object, the Game class instance.

Anyway, besides switching to another screen, we want the Ready Button to do much more. We want it to call some methods that will take care of the game’s settings. The methods will be defined in the root widget class, which is SettingsScreen.

The first method will set the players, so let’s name it set_players. The second method will set the slugs, so let’s name it set_slugs.

Finally, the third method should set the number of races (if the game should end after a given number of races) or the time of the game (if the game should end after a specified period of time). However, in this series I’m only going to show you how to implement the first ending condition, which means the game is always going to end when there’s only one player with any money left. The two other ending conditions are implemented in my book, so feel free to grab a copy for yourself. There, I mean in my book, the method is simply named set_game.

So, we’re going to add just the first two callback methods to the on_press event on the Ready Button instance and then implement them in the settings.py file. We could also implement them directly in the Game class in main.py, but I just want the methods used for settings to be in the Settings screen.

In this part we’ll take care of setting the players and in the next part we’ll set the slugs.

The set_players Method

The set_players method will take one argument, the list of players. So we must create the players property on the root widget. In the list we’ll put the four PlayerSettings instances, which we will reference by ids. We could also pass the four players directly as arguments to the method, but this way will be more concise. Here’s the kv file:

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

...

<SettingsScreen>:
    ...

    game: root.manager

    # Here we have the players property set to a list of players.
    # Each player is here represented by a PlayerSettings instance.
    # The instances are referenced by ids.
    players: [_player1, _player2, _player3, _player4]

    ...

                # the players rows
                # player 1
                PlayerSettings:
                    id: _player1
                    label_text: 'Player 1'
                
                # player 2
                PlayerSettings:
                    id: _player2
                    label_text: 'Player 2'

                # player 3
                PlayerSettings:
                    id: _player3
                    label_text: 'Player 3'

                # player 4
                PlayerSettings:
                    id: _player4
                    label_text: 'Player 4'
                
        ...

        ### READY BUTTON ###
        RedButton:
            text: 'Ready'
            on_press: 
                # The first method we want to call when this event is triggered
                # is the set_players method. It's defined in the SettingsScreen
                # class, so on the root widget. We pass the list of players 
                # (actually PlayerSettings instances) to it.
                root.set_players(root.players)

                # We still want the screen to change.
                root.manager.current = 'racescreen'

Now, by setting a player I mean assigning the name and initial money that we enter in the appropriate text inputs to the name and initial_money properties respectively. To do that, we have to modify the PlayerSettings rule. Here’s the code with comments:

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

<PlayerCount>:
    ...

<PlayerSettings>:
    # We will need two properties, one for the name text from the 
    # NameInput and one for the intial money text from the NumInput.
    # We will reference the two text inputs by ids.
    name: _player_name.text
    player_initial_money: _player_initial_money.text

    Regular80x30Label:
        text: root.label_text    
    NameInput:
        id: _player_name

        # Let's add a hint text for the app user so that they know
        # what kind of input is expected.
        hint_text: "Enter the name of " + root.label_text
    BoxLayout:
        RegularLabel:
            text: ""
            size_hint_x: None                
            width: 280                            
        DollarLabel:
        NumInput:
            id: _player_initial_money

            # Let's add a hint test for the app user with the default
            # amount of initial money. We could use a variable for that
            # in the SlugraceApp class, but this time let's just
            # hard-code it.
            hint_text: '1000'

<SettingsScreen>:
    ...

And now let’s implement the method in the settings.py file. But before we do that, there’s one more thing I’d like to talk about for a while. Each player will have a name and an amount of money at the beginning of the game. These pieces of information will be stored in the name and initial_money properties that we defined in the Player class. We want the name to be no more than 10 characters long. We also want the initial money to be between $10 and $5000. We could naturally hard-code these limitations, but instead I’ll use some variables for them on the application level, so in the SlugraceApp class. I decided to do it that way not only because hard-coding things doesn’t seem good practice in general, but also because I want to use this opportunity to show you how to access data defined on app level in any place in the code. You already know that in the kv files you can simply use the app variable, but this time I’ll show you how to do it in Python files. So, first let’s define the three variables in the SlugraceApp class in main.py:

# File name: main.py

...
             
class SlugraceApp(App):
    # General Settings
    initial_money_min = 10
    initial_money_max = 5000
    max_name_length = 10

    def build(self):
        return Game()    

if __name__ == '__main__':
    from kivy.core.window import Window
    Window.clearcolor = (1, 1, .8, 1)
    SlugraceApp().run()

The names of the variables are pretty self-explanatory, I think. We will be using the first two variables in this part and the third one a bit later, when we add text validation to our code.

And now let’s go to the settings.py file and implement the set_players method. You will find the explanations in comments:

# File name: settings.py
...
class SettingsScreen(Screen):
    # Here's the method used for the players settings. 
    def set_players(self, players):
        # In this method we will be using the three variables that we just defined
        # in the SlugraceApp class. To access the class in Python we have to call 
        # the get_running_app method defined in the App class. 
        from kivy.app import App
        app = App.get_running_app()

        # Now we will iterate over the players stored in the players list in the Game
        # class. 
        for i, player in enumerate(self.game.players):

            # First let's set each player's name. If the text input for the name was
            # left empty, so when the app user did not enter a name for a particular
            # player, the player's name will be set to something generic like Player 1,
            # Player 2, etc. 
            player.name = 'Player ' + str(i + 1) if not players[i].name else players[i].name

            # Now let's set the player's initial money. As you remember it may be any value
            # between $10 and $5000. These two extreme values are saved in the two variables
            # we created in the SlugraceApp class, initial_money_min and initial_money_max.
            # Now we can easily access these variables using the app variable we just created
            # at the beginning of this method.
            player.initial_money = (1000 if not players[i].player_initial_money 
                else max(app.initial_money_min, 
                    min(int(players[i].player_initial_money), app.initial_money_max)))

            # When the game begins, a player's money is the same as initial money. 
            player.money = player.initial_money  

In the next part of the series we’ll take care of slug settings. And now let’s make the players’ data that was set in the Settings screen visible in the other screens.

Player Data in the Other Screens

After we choose some names for the players and assign them some initial money, we want this infomation to be visible in several places throughout the application. The first place is the Players’ Stats area in the Race screen. Here we need the players’ names and their current money, which is stored in the money property.

Players’ Stats

So, let’s go to the race.kv file and find the Players’ Stats area. It should look like this:

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

...

<RaceScreen>:
    ...
                            
            # Players' Stats           
            BoxLayout:
                ...

                PlayerStats:
                    name: 'Player 1'
                    money: 1000        

                PlayerStats:
                    name: 'Player 2'
                    money: 800    

                PlayerStats:
                    name: 'Player 3'
                    money: 1300    

                PlayerStats:
                    name: 'Player 4'
                    money: 1200                         
            
            # Buttons
            ...

As you can see, the name and money properties on the PlayerStats instances are set to some hard-coded values. We want them to be set to the values that we set in the Settings screen. It’s easy to fix:

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

...

<RaceScreen>:
    ...
                            
            # Players' Stats           
            BoxLayout:
                ...

                BoldLabel:
                    text: "Players' Stats"   

                PlayerStats:
                    # We access the Game class through root.game.
                    name: root.game.player1.name
                    money: root.game.player1.money      

                PlayerStats:
                    name: root.game.player2.name
                    money: root.game.player2.money  

                PlayerStats:
                    name: root.game.player3.name
                    money: root.game.player3.money  

                PlayerStats:
                    name: root.game.player4.name
                    money: root.game.player4.money          
            
            # Buttons
            ...

Now let’s check out if it works. Run the app and set the names and initial money values for some of the players:

settings screen

When you hit the Ready Button, the names of the Players will be set to Jenny, Player 2, Mike and Player 4. The initial money and money values of the first two players will be set to $3000 and $2000 respectively and to the default $1000 for the other two. These data should be now visible in the Race Screen, in the Players’ Stats area. Press the Ready Button. You should see this:

race screen

The Bets Screen

The next place where the player data should be visible is in the Bets screen. Here’s the code we have now:

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

... 

<BetsScreen>:
    ...

        ### PLAYER BETS ###
        BoxLayout:
            orientation: 'vertical'

            # player 1
            Bet:
                player_name: 'Player 1' 
                bet_amount: 1000
                max_bet_amount: 1000 
                player_group: 'player1'

            # player 2
            Bet:
                player_name: 'Player 2' 
                bet_amount: 1000
                max_bet_amount: 1000 
                player_group: 'player2'

            # player 3
            Bet:
                player_name: 'Player 3' 
                bet_amount: 1000
                max_bet_amount: 1000 
                player_group: 'player3'

            # player 4
            Bet:
                player_name: 'Player 4' 
                bet_amount: 1000
                max_bet_amount: 1000 
                player_group: 'player4'

        ### GO BUTTON ###    
        ...

As you can see, here the names of the players are again set to the generic names which should be used only if no other name is entered. You can change it by accessing the Player objects in the Game class, just like you did before.

You should also change the values of the max_bet_amount property on each Bet instance. A player can’t bet more than they have, so this value should be set to the player’s money amount.

So, here’s the code:

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

...

<BetsScreen>:
    ...

        ### PLAYER BETS ###
        BoxLayout:
            orientation: 'vertical'

            # player 1
            Bet:
                player_name: root.game.player1.name 
                bet_amount: 1000
                max_bet_amount: root.game.player1.money 
                player_group: 'player1'

            # player 2
            Bet:
                player_name: root.game.player2.name 
                bet_amount: 1000
                max_bet_amount: root.game.player2.money 
                player_group: 'player2'

            # player 3
            Bet:
                player_name: root.game.player3.name 
                bet_amount: 1000
                max_bet_amount: root.game.player3.money 
                player_group: 'player3'

            # player 4
            Bet:
                player_name: root.game.player4.name 
                bet_amount: 1000
                max_bet_amount: root.game.player4.money 
                player_group: 'player4'

        ### GO BUTTON ###    
        ...

Let’s check it out again. Run the app and set some players’ names and initial money values:

settings screen

Now when you hit the Ready Button, the new settings should be visible in both the Players’ Stats and in the Bets screen:

race screen

The Results Screen

Yet another place where the player data should be visible is the Results screen. Here’s the code as it is now:

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

<ResultsScreen>: 
    ...

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

    ...

        ### PLAYER RESULTS ###   
        BoxLayout:
            orientation: 'vertical'

            # player 1
            Result:
                player_name: 'Player 1'
                money_before: 1000
                bet_amount: 300
                slug_name: 'Speedster'
                result_info: '- won'
                gain_or_loss: 400
                current_money: 1400
                odds: 2.54

            # player 2
            Result:
                player_name: 'Player 2'
                money_before: 1000
                bet_amount: 300
                slug_name: 'Speedster'
                result_info: '- lost'
                gain_or_loss: 400
                current_money: 600
                odds: 1.59

            # player 3
            Result:
                player_name: 'Player 3'
                money_before: 1000
                bet_amount: 300
                slug_name: 'Trusty'
                result_info: '- won'
                gain_or_loss: 400
                current_money: 1400
                odds: 2.24

            # player 4
            Result:
                player_name: 'Player 4'
                money_before: 1000
                bet_amount: 300
                slug_name: 'Speedster'
                result_info: '- lost'
                gain_or_loss: 400
                current_money: 600
                odds: 1.85
                    
        ### NEXT RACE BUTTON ###    
        ...

At this moment we can change two things, player_name and current_money. Just set them to the players’ name and money properties respectively. OK, here’s the code:

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

<ResultsScreen>: 
    ... 

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

    ...

        ### PLAYER RESULTS ###   
        BoxLayout:
            orientation: 'vertical'

            # player 1
            Result:
                player_name: root.game.player1.name
                …
                current_money: root.game.player1.money
                odds: 2.54

            # player 2
            Result:
                player_name: root.game.player2.name
                ...
                current_money: root.game.player2.money
                odds: 1.59

            # player 3
            Result:
                player_name: root.game.player3.name
                ...
                current_money: root.game.player3.money
                odds: 2.24

            # player 4
            Result:
                player_name: root.game.player4.name
                ...
                current_money: root.game.player4.money
                odds: 1.85
                    
        ### NEXT RACE BUTTON ###    
        ...

Let’s check it out again. Run the app like before and enter some data in the Settings screen:

settings screen

Hit the Ready Button to go to the Race screen. Here you should see the player data in the Players’ Stats area and in the Bets screen, just like before:

results screen

Now hit the Go Button in the Bets screen and you will see the player data in the Results screen as well:

results screen

And now let’s move on to set the slugs.


Spread the love

Leave a Reply