Programming

Make a Snake game for Android written in Python – Part 3

I hope you enjoyed the first two sections of the tutorial. If you got through it, rest assured that the hardest part is behind us. The game engine is at 90% done at that point, and handling screens is very straightforward in kivy. We’re just going to make a few arrangements here before packaging the app. It’s a good front-end exercise because this time we’ll rely a lot more on the kivy language.

Creating the screens

Our application requires two screens : one for the welcome screen and one for the playground. I don’t count the widget where we’re going to display the options as a screen because it will be a popup placed on the welcome screen. First we will specify the layout of our widgets in the .kv file, and only then write the corresponding classes in Python.

Front-end :

The PlaygroundScreen is the easiest : it only contains the playground !

Screenshot_2015-02-04-20-27-39

The main screen will be composed of several internal widgets that will help us organize the three main elements : the title of the App (I chose Ouroboros but feel free to call it what you want), a Play button that triggers the entry of the PlaygroundScreen and an Option button calling the Option popup. Layouts will help us organize these elements in term of dimensions and positioning.

Screenshot_2015-02-04-20-16-16

The option popup will occupy 3/4 of the welcome screen. It will contain the widgets needed to interact on the parameters and a Save button. We’ll add the options per se afterward. For now we’re just preparing the layout.

Back-end :

Let’s add the Python counterparts of the classes we defined in the kivy language, and the behavior we want to give them. Both screens will inherit from Screen (what a surprise) and the OptionsPopup from Popup (again, how baffling).

The Welcome screen requires only one method : show_popup() that will be called when the Options button is pressed on the main screen. We don’t have to define anything else for the Play button because it will use the ability of its parent to access the screen manager. Yay Kivy ! Since we’ll act on the OptionsPopup, its instance will be stored as a property.

The GameScreen contains the Playground. Recall how in the last part we started the game on App start. We don’t want that anymore : the Welcome screen should be shown on App start, and the game should start only when the Playground comes into view. Thus you can delete the on_start() method from the main class and transfer the afferent logic here :

We might as well prepare the OptionsPopup class right now. We have to anyway otherwise the bindings we’re going to make in a few steps wont work properly.

Our screens are ready. Good. What we want now is to add a ScreenManager to the App and to register the two screens. When we wanted to interact with an object after its instanciation, we usually declared it as an instance property of the object holding it. Here we’re going to declare the screen manager at the class level because we’ll need to call it without any direct reference to the parent holding it (we’ll be able to call the parent class, but not the object directly).

Give it a run : the welcome screen appears but hey, nothing happens if we press the buttons ! Maybe we should think of adding some bindings. Back to snake.kv. We’re going to specify a behavior for the on_press() event of the buttons. Play will tell the screen manager to switch to the playground and Options will trigger the show_popup() method we just defined. Don’t forget the button of the options popup : it will simply dismiss its parent widget.

One more thing : how do we get back to the main menu when we’re in game ? Indeed, at that point we’re stuck on the playground as soon as we reach it. In order to keep things simple, we’ll just call a change of screen if the game is lost.

Full code.

Try your new build : it’s starting to look like something isn’t it ? One more step and we’ll be ready to package !

Adding the options

We’re going to add two options :

  • Borders : at the moment the game is lost is the snake goes outbound, but in the snake I remember you could also choose to disable the borders (it even was the default setting wasn’t it?). In that case, the snake would reappear on the other side. Let’s implement that.
  • Speed : we set the duration of each turn to 1 second. We’re going to allow the user to choose from a predefined range of values its starting speed. Furthermore, we will add a mechanism so that the speed increases each time a fruit is eaten.

It will look like that :
Screenshot_2015-02-04-20-28-02

Adding the necessary widgets to our options popup :

Before modifying the OptionPopup class so that it can dispatch its options, we have to prepare our game engine to receive them. What changes do we need to make ? First, add properties so that we can receive the option’s values. Then modify start() : if the border option is on, we’ll draw a line around the Playground to symbolize it. We’ll also compute the refresh rate based on the speed option. What else ? reset() will require a tweak too. Oh, and we have to add a new method to handle the snake re-positioning if the border option is off and it exits the screen, in which case it must reaper on the opposite side.

Complete the OptionsPopup so that it passes on its values when we dismiss it :

Full code.

My friends, I think we’re ready to install our app on our favorite Android smartphone ! Mine is a Sony xperia z3 compact if ever you were wondering. I really that this size of screen. Anyhow, I’m digressing.

Packaging

If you read part 1, you know the drill.

Update the buidlozer.spec file with the title, name and domain of your app.
Set the version.
Fire up a console, navigate to your folder :

Final code

2 Comments

  1. Salut Alexis,
    congratulations for your tutorial !
    I found it very informative and the code is well built .
    In the part 1 I think you should specify the version of Python

    “this solution is not very elegant. But it works” =>I often tell me that , when I use Kivy 🙂

    1. Merci beaucoup.
      You’re very right about the version. I’m going to correct that right now.

      Since you’re a kivy user, I have question : someone commented on reddit “I recommend avoiding Kivy like the plague on Android” because of its inefficiency compared to a native solution. Is that true ? Am I wasting my time learning it ?

Leave a Reply