Android:Game Programming
上QQ阅读APP看书,第一时间看更新

Chapter 9. Making Your Game the Next Big Thing

The day has finally come when we can publish our first game. This chapter, despite being shorter than others, is probably the longest chapter to complete. It would be a good idea to scan through the different exercises to see what is involved before actually diving into them. Most of these tutorials are not suitable to do during the advertisements of your favorite TV program or when you get in from work and you are really tired.

Read the chapter and make a plan of when to perform each stage. The stages are arranged so you should be able to leave the project in between each of them. If you are really determined, have understood all the code until now, are confident with files and folders, and have no interruptions, you can probably get the work in this chapter completed in about a day.

As always, the completed code is in the relevant folder in the download bundle, in this case the Chapter9 folder.

Note

Note that because I cannot share the login credentials for my developer account, had to mask some ID numbers within the code with a series of black lines. You will see these in the code in this chapter when talking about the ids.xml file which is NOT in the code bundle because of its confidential nature. However, as you will see in the Setting up the Snake project ready for implementation section, it is easy to get your own ID codes. Also note that a lot of the work in this chapter involves set up that takes place in your developer console. The leaderboards and achievements will not function until you have completed the necessary steps. However, you can review the entire code in the Chapter9 folder and download the enhanced version of the game from Chapter 8, The Snake Game, complete with working leaderboards and achievements from Chapter 9, Making Your Game the Next Big Thing, from https://play.google.com/store/apps/details?id=com.packtpub.enhancedsnakegame.enhancedsnakegame.

If you want to implement everything yourself and also want to start with the enhanced version of the game, including all the improvements from the self-test questions from the previous chapter, then grab the EnhancedSnakeGame code from the Chapter8 folder, and update your working project from Chapter8.

In this chapter, you will learn the following topics:

  • How to publish your app
  • Marketing your app, including making it social with leaderboards and public achievements
  • Implementing leaderboards and achievements with the Google Play Game Services API
  • Looking at what to do next depending on what you want to achieve

How to publish your app

Some of the steps in this guide involve writing descriptions and supplying screenshots, so you might like to read through the entire guide before implementing any of the steps:

  1. Create an icon. Exactly how to design an icon is beyond the scope of this book, but simply put, you need to create a nice image for each of the Android screen density categories. This is easier than it sounds. Using a simple image, such as the snake head bitmap, you can customize and download a set from http://romannurik.github.io/AndroidAssetStudio/icons-launcher.html. There are many sites that offer a similar free service. Of course, you can just use the images in the enhanced snake project, and skip this step and the next.
  2. Once you have downloaded your .zip file from the preceding link, you can simply copy the res folder from within the download to the main folder within the project explorer. All icons at all densities will now be updated.
  3. Before we proceed further, optionally you will need to prepare some screenshots of the game. You will be prompted to upload a screenshot for several screen types, but since the game is nearly identical on all screen types, one image should do fine. You will also need an image of dimension 512 x 512 for a high-resolution icon and an image of dimension 1024 x 500 for a feature graphic. They don't need to be great, but you do need them to proceed. Create your own or grab a copy of my very simple graphics in the Chapter9 folder.
  4. Now, unfortunately, you will need to spend $ 25 to open a Google Play account. You can sign up at https://play.google.com/apps/publish/.
  5. Once you have signed up, you can log in to your developer console at the same URL as mentioned in the previous step.
  6. Once in your console, click on the + Add new application button:
  7. In the Add New Application dialog, type a name for your application, such as Snake Game. Now click on Upload APK.
  8. We now need to make our app into the release version. Open the AndroidManifest.xml file and add the highlighted line of code in the location shown:
    <application
            android:debuggable="false"
            android:allowBackup="true"
  9. Rebuild your signed APK for the latest version of the Snake game, as discussed in Chapter 2, Getting Started with Android.
  10. Now click on Upload your first APK to production.
  11. Now go to your Snake game APK.
  12. Wait for the APK to finish uploading. You can now see your game summary screen. Notice the highlighted progress indicator to the top-left corner of the next image. We have a green tick, indicating that the APK has been uploaded successfully:
  13. The next thing we need to do is configure our Store Listing, so click on the Store Listing link, just below the APK link.
  14. Write a short description and a long description. Also upload your screenshots, feature graphics, and high-resolution icon.
  15. In the Application Type drop-down menu, select Games. In the Category drop-down menu, Arcade is probably most appropriate. For Content Rating, select Everyone, and for Privacy Policy, click on the checkbox for Not submitting a privacy policy at this time.
  16. Add your website and email address to the relevant boxes.
  17. Back at the top of the web page, click on the Save button.
  18. Now we are at the final stage of this guide. Click on the Pricing and distribution link. It is just underneath the Store Listing link from step 13.
  19. Click on the Free button at the top of the page.
  20. Click on the checkbox of all the countries you want your game to be listed in.
  21. Scroll down to the bottom of the page and click on the checkboxes for Content guidelines and US Export laws.
  22. Click on Save at the top of the page.
  23. Finally, from the Ready to publish drop-down menu at the top right corner of the page, click on Publish this app and you are done.

Congratulations! Your game will be live on Google Play somewhere between the next 5 minutes and 24 hours.

Marketing your app

The temptation at this stage is to sit back and wait for our game to hit the top position in the best-selling apps. This never happens.

To ensure that our app achieves its full potential, we need to do the following continuously:

Improve it

We have already made quite a few improvements to the Snake game but there are many more, such as difficulty settings, music, debugging (did you see the occasionally wonky body segments?), settings menu, and so on. You can pay a professional to design backgrounds and sprites, or add more sound effects. When you have improved your Android and Java skills further, you can rewrite the entire game using a smoother engine and call it Version 2.

Promote it

This could be the subject of another book but there are so many ways we can spread the word about our app. We can create a page/profile on all the social media sites—Facebook, Twitter, Flickr, and so on. Add regular updates, announcements, challenges (see compulsion). We can create a website to promote our app and promote it in all the ways we would promote any other website. We can add a message in the app itself asking players to rate it, perhaps pop up a message just after they have got a high score or achievement. We can ask everyone we know and everyone who visits our social media/website to give a rating and leave a review. There are many more ways to promote an app as well. The secret to all of them is this: keep doing it. For example, don't create a Facebook page and then expect it to grow in popularity on its own. Keep adding to all of your channels of promotion.

Keep the players' level of compulsion

Besides improving the game in the ways we have briefly mentioned, we need to give players a compelling reason to keep coming back to our game. One way might be to add new levels. For example, it won't be hard to implement levels in our Snake game. Each level could have walls in different places and the layouts could get progressively more challenging. All we would need to do is make an array of obstacles, draw them on the screen, and detect collisions. Then set a target for the snake length for each level and move on to the next level when it is achieved.

We could offer different snake designs to be be unlocked for certain challenges. How about the player saving all the apples they collect as a form of currency, and then strategically spending that currency to get a chance to continue after they have died?

How about offering time-limited challenges? For example, complete level 10 by the end of the month to receive a thousand bonus apples. Perhaps, we could come up with more things the apples could be spent on. Cool snake accessories or levels that can only be unlocked with apples. The point is that all of this compulsion can be added and updated at the same time as we upload our improvements. Nothing mentioned in this discussion about compulsion would be unachievable with the skills we have learned so far.

Probably, the most compelling aspect we can add to our game is online leaderboards and achievements so that players can compare themselves to their friends and the rest of the world. Google is aware of this and have done a lot of work to make it as easy as possible to add leaderboards and achievements to games. We will see how we can yet again take advantage of other people's hard work.

What's more, all the achievements that players of your game earn are fed into their overall Google Play profile. Here is a screenshot of my rather poor Google Play achievements profile:

You might have noticed a few Snake achievements in that lot. This feature makes your game potentially even more compelling.

Tip

Let's do a quick reality check—I am not actually suggesting that you spend significant amounts of time trying to make a real business out of our humble Snake game. It just serves as a useful example for discussion. Also, if we can come up with so many ideas for a game this old and simple, then we can surely come up with some really amazing stuff for a game we are passionate about. When you have an idea you are passionate about, then that would be the time to go for it and expand the brief marketing plan we have discussed.

Adding leaderboards and achievements

So we know why leaderboards and achievements are a good thing. The first thing we need to do here is plan our achievements. A leaderboard is a high score table, and that's it! There isn't a great deal of things we can do to make them different. The achievements, however, deserve some discussion.

Planning the Snake achievements

At first, it might seem that a really simple implementation of a really simple game, like our Snake game, isn't deep enough to have many, or even any, achievements. So what follows is a quick brainstorming session of achievement ideas:

  • Score 10, 25, 50, 100, and so on: Simply unlock achievements at different levels of high score.
  • Snake length: Simply unlock achievements at different snake lengths.
  • Cannibal: Unlock an achievement the first time the player collides with their own tail segment.
  • Collect x apples in total: Keep a tally of all the apples ever collected, and unlock achievements at significant milestones.
  • Play 10, 25, 50, 100 games: Reward the player for keeping on going. Whether they win or lose, achievements are unlocked for effort.
  • Treasure hunt: What if there was a hidden spot in every game? It could give the player a reason to explore each level. They could be rewarded with points and apples. They could then unlock real achievements, perhaps for every 5, 10, or 20 hidden spots that they find.

Some of the achievements suggest that we would be required to keep a record of the player's progress. Surprisingly, Google Play Game Services can actually do this for us. These are known as incremental achievements. The number of apples collected in total is a good example of an incremental achievement. Others, such as snake length, are just dependent on the player's performance in any one game.

We will implement the total number of apples and the snake length achievements so that we can see how to implement both types.

We can have five achievements for reaching each of the following snake lengths: 5, 10, 20, 35, and 50. There can also be five incremental achievements for the total number of apples collected. Specifically, the player will get an achievement at 10, 25, 50, 100, 150, and 250 apples collected. Soon, we will see how to do it.

Finally, we need to decide how many points each achievement will be worth, out of the 1,000-point limit per game. As I might come back and add some more achievements later I am going to allocate 250 points to the apples' achievements, like this:

I will also allocate 250 points to the snake length achievements, as shown in the following table:

Once you see how to implement these achievements in both the code and the developer console, it will be fairly simple to design and implement your own different achievements.

Step-by-step leaderboards and achievements

This is probably the longest part of the book to complete. However, once you have been through this process, it will be significantly easier the next time you do it.

Installing the Google Play Services API on your PC

First, we need to add the tools and the libraries needed to use the Game Services classes. This is nice and easy with Android Studio:

  1. Click on the SDK Manager icon in the Android Studio toolbar:
  2. The SDK manager will start. It looks a bit like this:
  3. Scroll to the very bottom and underneath Extras, you will see Google Play Services. Check the box that is shown as highlighted in the following screenshot by clicking on it:
  4. Now click on the checkbox for Google Repository, just below Google Play Services.
  5. Click on Install packages and wait for the packages to download and install.
  6. Save your project and restart Android Studio.

We now have the tools installed to start developing Google Play Game Services apps. Next, we need to set up our developer console to communicate with our app, ready for the features we will soon write code for.

Configuring the Google Play developer console

Here, we will prepare your developer console by creating a new Game Services application. This might sound a little counterintuitive; surely, Snake is our application, isn't it? Yes, but Google Play is structured in such a way that you create a Game Services application, and it is with this application that your actual games (Snake in this case) will communicate. It is the Game Services application that will have the achievements and leaderboards that we will award and display from our Snake Game:

  1. Log in to your Google Play developer console at https://play.google.com/apps/publish/.
  2. Click on the Game services tab on the left of the web page.
  3. Now click on the Add a new game button.
  4. Enter Snake as the name of your game and choose Arcade from the Category drop-down menu. Now click on Continue. All of this is shown in the next screenshot:
  5. Now we can configure our game. Type a game description in the Description field, and add the same high-resolution icon and feature graphic that we added when we uploaded the game.
  6. Click on the Save button at the top of the screen.
  7. Now we will link our Snake Game Services app with our actual Snake game. On the left of the web page, click on the Linked apps tab.
  8. Google Play Game Services can be used with almost any platform, even Apple. We are using it for Android here, so click on the Android button.
  9. All we need to do on this screen is click on the Package Name search box and click on our Snake game option.
  10. Click on Save and continue at the top of the screen.
  11. We're nearing the end of this phase. Click on Authorize your app now and review the information.
  12. Finally, click on Continue.

We now have a Google Game Services app set up, and linked to our Snake game.

Implementing the leaderboard in the Google Play developer console

Now we need to create our leaderboard in our developer console so that we can later interact with it in our Java code:

  1. Log in to your developer console.
  2. Click on Game Services, then on Snake, and then on Leaderboards.
  3. Now click on Add Leaderboard. This is the NEW LEADERBOARD screen:
  4. This might look like a bit of a marathon ahead, but all we need to do is enter a name (Snake will do) in the Name field, and we are done. It might seem strange entering a name for our leaderboard, but this is because it is possible to have multiple leaderboards for one game.
  5. Read through all the options. You will see that they are just right for us and no further action is required. Click on Save.

Our leaderboard is now ready to communicate with our Snake app.

Implementing the achievements in the Google Play developer console

Here, we will set up in our developer console the achievements that we discussed previously.

You might like to prepare some graphics to represent each of these achievements. They need to be 512 x 512 pixels each. Alternatively, you can use an enlarged apple bitmap and perhaps a snake body segment for the apples and snake length achievements, respectively:

  1. Log in to your developer console. Click on Game Services, then on Snake, and then on Achievements.
  2. Click on Add Achievement and you will see the New Achievement screen:
  3. As we are implementing the incremental apple achievements, the first thing to do is to enter something in the New Achievement form. In the Name field, enter Apple Muncher 1.
  4. In the Description field, enter Munch 10 apples.
  5. Click on the Add Icon button and select your preferred 512 x 512 graphic.
  6. Click on the Incremental achievements checkbox and enter 5 in the How many steps are needed field. This is because the first achievement is for eating 5 apples. This step is shown in the next screenshot:
  7. Enter 10 for the number of achievement points in the Points field.
  8. Click on Save and repeat steps 2 to 7 four more times for all the apple achievements, varying the Name, Description, How many steps are needed?, and Points fields as per our plans and tables of values for achievements.
  9. Now we can move on to our snake length achievements. Click on New Achievement. In the Name field, enter Super Snake 1.
  10. In the Description field, enter Grow your snake to 5 segments.
  11. Click on the Add Icon button and browse to your preferred image.
  12. Finally, enter 10 for the number of achievement points in the Points field.
  13. Click on Save and repeat steps 9 to 13 four more times for each of the snake length achievements, varying the Name, Description, and Points fields as per our plans and tables of values for achievements.

We have now set up our achievements, ready to be implemented in code.

Setting up the Snake project ready for implementation

What we will do in this section is prepare our app to communicate with the Google Play servers:

  1. Add this highlighted code to the AndroidManifest.xml file, just before the closing </application> tag:
    <meta-data android:name="com.google.android.gms.games.APP_ID"
     android:value="@string/app_id" />
    <meta-data android:name="com.google.android.gms.version"
     android:value="@integer/google_play_services_version"/>
    
    </application>
  2. Create the ids.xml file in the values folder in the Project Explorer. Now you need to get your unique code for your game to go to this file. Log in to your developer console, click on Game Services, and then click on Snake. Now click on Achievements.
  3. Just below your list of achievements is a small Get resources link:
  4. Click on the Get resources link.
  5. Copy and paste the code into the ids.xml file. Then click on the Finished button in the developer console.
  6. Now we need to get four code files from the Google Play Game Services GitHub repository. We will copy and paste the files directly into our project.
  7. Create three new empty files in the java folder. Right-click on GameActivity in the project explorer and navigate to New | Java class file. Name the new file BaseGameActivity. Repeat this step and name the file GameHelper. Repeat this once more and name the file GameHelperUtils.
  8. Now we will get the Java code to copy into the three files we just made. To get the code for BaseGameActivity.java, visit https://github.com/playgameservices/android-basic-samples/tree/master/BasicSamples/libraries/BaseGameUtils/src/main/java/com/google/example/games/basegameutils, where you can see further links to the code for the three files we created in step 7:
  9. Click on BaseGameActivity.java as shown in the preceding screenshot. Select all of the code and copy and paste it into the identically named file that we created in Android Studio. Note that when we created the file, Android Studio created some basic template code. We need to delete all of this, except our package name at the top. When we paste in the copied code, we need to delete the Google package name.
  10. Click on GameHelper.java, as shown in the previous screenshot, and repeat step 9.
  11. Click on GameHelperUtils.java, as shown in the preceding screenshot, and repeat step 9.
  12. There's one more file to create. Right-click on the values folder in the project explorer. Navigate to New | File. Name the file gamehelper_strings.xml.
  13. Get the code that we need for this file in the same way as we did for the previous three Java files from but from this link: https://github.com/playgameservices/android-basic-samples/blob/master/BasicSamples/libraries/BaseGameUtils/src/main/res/values/gamehelper_strings.xml.
  14. Paste the code in gamehelper_strings.xml, which we created in step 12.
  15. Now change the MainActivity declaration in the MainActivity.java file.

    Consider this code:

    public class MainActivity extends Activity {

    Change it to the following code so that we can now extend the version of Activity that handles all the hard work of the Game Services API:

    public class MainActivity extends BaseGameActivity {
  16. Now check out the code in the GameActivity.java file:
    public class GameActivity extends Activity {

    Change the preceding code to the following code so that we can now extend the version of Activity that handles all the hard work of the Game Services API:

    public class GameActivity extends BaseGameActivity {
  17. Notice that for both Activities, we have an error in the class declaration we just typed. If you hover the mouse cursor over the code we typed in the previous step, you can see the reason. We need to implement some abstract methods of a class we are using. Recall from Chapter 6, OOP – Using Other People's Hard Work, that if a method in a class is declared abstract, then the class that extends it must implement it. That's us! Let's perform an empty implementation for now. Right-click on the line of code with the error and navigate to Generate | Implement Methods. Now click on OK. Perform this step for the MainActivity.java file and the GameActivity.java file. Our empty methods are now ready for our code. We will write the code in the next tutorial.
  18. Next, using the project explorer, find the build.gradle file. Be careful; there are two files with the same name. The file that we need to find is a couple of lines below the AndroidManifest.xml file. It is highlighted in the next screenshot. Open it by double-clicking on the build.gradle file:
  19. Find the section of code shown here and add the line that is highlighted. This makes all the classes we downloaded in the previous guide available for use in our Snake game:
    dependencies {
        compile 'com.google.android.gms:play-services:+'
        compile 'com.android.support:appcompat-v7:+'
        compile fileTree(dir: 'libs', include: ['*.jar'])
    }

Okay, I agree that was a fairly tough tutorial, but we are now ready to implement our code in three final steps:

  1. Player sign-in and buttons.
  2. Leaderboards.
  3. Achievements.

We will then be able to upload our updated app and use our new leaderboards and achievements.

Implementing the player's sign-in, achievements, and leaderboard buttons

By the end of this section, players will be able to log in through the game to our empty leaderboards and achievements. The guides that follow this section will actually make the leaderboards and achievements work.

  1. First, let's enable our Game Services. All of the work we have done so far in the developer console needs to be published before we can use it. Log in to your developer console. Navigate to Game Services | Snake | Ready to publish | Publish game. Then you will be shown a Publish your game button. Click on it. Finally, read the brief disclaimer and click on Publish now.
  2. Now we need to build a UI that has Sign in, Sign out, Leaderboards, and Achievements buttons. Open the layout_main.xml file and edit it on the Text tab of the editor window by adding the following code. Obviously, there is a lot to type. You might like to copy and paste the code from the download package at Chapter9\EnhancedSnakeGame\layout. Here is the code. Type it in or copy and paste it:
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        tools:context="com.packtpub.enhancedsnakegame.enhancedsnakegame.MainActivity">
    
        <Button
    
            android:id="@+id/llPlay"
            android:layout_width="140dp"
            android:layout_height="wrap_content"
            android:text="Leaderboards"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            android:visibility="gone"/>
    
        <Button
            android:id="@+id/awardsLink"
            android:layout_width="140dp"
            android:layout_height="wrap_content"
            android:text="Achievements"
            android:layout_gravity="center_vertical"
            android:layout_alignTop="@+id/llPlay"
            android:layout_toLeftOf="@+id/llPlay"
            android:visibility="gone"/>
    
    
        <!-- sign-in button -->
        <com.google.android.gms.common.SignInButton
            android:id="@+id/sign_in_button"
            android:layout_width="140dp"
            android:layout_gravity="center_horizontal"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
             />
    
        <!-- sign-out button -->
        <Button
            android:id="@+id/sign_out_button"
            android:layout_width="140dp"
            android:layout_height="wrap_content"
            android:text="Sign Out"
            android:layout_alignParentTop="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            android:layout_gravity="center_horizontal"
            android:visibility="gone"
            />
    
    </RelativeLayout>
  3. Explaining the code line by line is beyond the scope of the book, but this is not much different from the code we have been autogenerating when using the UI designer since and its position on the screen. You can switch to the design tab and move the buttons around to suit yourself. Note that the reason some of the buttons are not visible in the designer is that they are hidden until the player signs in. The reason we have done things this way is to make sure we implement the sign in button in just the right way. Note the id attribute for each of the buttons. We will be manipulating them in our Java code next. With some buttons set to visibility = gone, we see something like this:
  4. With some buttons set to visibility = visible, we see something like what is shown in the following screenshot:
  5. You might be wondering why we are designing a UI when SnakeAnimView is what the user sees. We could have implemented all our own buttons with bitmaps and used their screen coordinates to detect presses, but what we will do now is load our UI on top of SnakeAnimView, which will greatly simplify things. Switch to the MainActivity tab in the editor window.
  6. First of all, we want to implement the onClickListener interface to handle our button clicks. To achieve this, change the class declaration to this:
    public class MainActivity extends BaseGameActivity implements View.OnClickListener{
  7. Now we can get Android Studio to quickly implement the required onClick method by right-clicking on the class declaration, navigating to Add | Implement methods, and then clicking on OK.
  8. Immediately after the previous line of code, we declare our four new buttons. Add this code after the code in the previous step:
    //Our google play buttons
        Button llPlay;
        Button awardsLink;
        com.google.android.gms.common.SignInButton sign_in_button;
        Button sign_out_button;
  9. In the onCreate method, just after the call to the setContent view, we use an object of the LayoutInflater class to load our UI on top of our SnakeAnimView. Add the highlighted code after the call to setContentView:
    setContentView(snakeAnimView);
    
     //Load our UI on top of our SnakeAnimView
     LayoutInflater mInflater = LayoutInflater.from(this);
     View overView = mInflater.inflate(R.layout.activity_main, null);
     this.addContentView(overView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    
  10. Immediately after the code in the previous step, we can get a reference to all our buttons and listen to clicks in the usual way:
    //game services buttons
            sign_in_button = (com.google.android.gms.common.SignInButton)findViewById(R.id.sign_in_button);
            sign_in_button.setOnClickListener(this);
            sign_out_button = (Button)findViewById(R.id.sign_out_button);
            sign_out_button.setOnClickListener(this);
            awardsLink = (Button) findViewById(R.id.awardsLink);
            awardsLink.setOnClickListener(this);
            llPlay = (Button)findViewById(R.id.llPlay);
            llPlay.setOnClickListener(this);
  11. Remember that in the previous guide, we overrode two abstract methods that we inherited when we extended the BaseGameActivity class. Now we will put some code into their implementation. The code is very straightforward. We hide the sign out button and show the sign in button when the sign-in fails, and we hide the sign in button and show all the other three buttons when the sign-in succeeds. Here are the two methods in their entirety. Type the highlighted code within the methods shown:
    @Override
        public void onSignInFailed() {
            // Sign in failed. So show the sign-in button.
     sign_in_button.setVisibility(View.VISIBLE);
     sign_out_button.setVisibility(View.GONE);
        }
    
        @Override
        public void onSignInSucceeded() {
            // show sign-out button, hide the sign-in button
     sign_in_button.setVisibility(View.GONE);
     sign_out_button.setVisibility(View.VISIBLE);
     llPlay.setVisibility(View.VISIBLE);
     awardsLink.setVisibility(View.VISIBLE);
        }
  12. Now we deal with the onClick method and what happens when the player clicks on any one of our four buttons. First, we type the code for our switch block. We will fill in the case statements in the next step:
    switch (v.getId()) {
    
    }
  13. Here, we handle the sign in button. We simply call the beginUserInitiatedSignIn method. It is implemented for us in the BaseGameActivity class. Type this code in the switch block from the previous step:
        case R.id.sign_in_button:
                    // start the sign
                    beginUserInitiatedSignIn();
                    break;
  14. Now we handle what happens when the player signs out. We just call signOut, which is implemented for us in the BaseGameActivity class. We then hide all our buttons and show the sign in button again. Type the following code after the code from the previous step:
    case R.id.sign_out_button:
                    // sign out.
                    signOut();
    
                    // show sign-in button, hide the sign-out button
                    sign_in_button.setVisibility(View.VISIBLE);
                    sign_out_button.setVisibility(View.GONE);
                    llPlay.setVisibility(View.GONE);
                    awardsLink.setVisibility(View.GONE);
                    break;
  15. Next, we handle what happens when the player clicks on the achievements button. One line of code gives us all of the achievement functionality. This is what OOP is all about—someone else's hard work doing everything for us. Type this code after the preceding code:
    case R.id.awardsLink:
    
                    startActivityForResult(Games.Achievements.getAchievementsIntent(getApiClient()), 0);
    
                    break;
  16. Finally, we handle what happens when the player clicks on the Leaderboards button. Again, one line of code gives us all of the leaderboard's functionality:
    case R.id.llPlay:
                            startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), getResources().getString(R.string.leaderboard_snake)),0);
                            break;

We explained the code as we went, but let's summarize:

  1. We designed a simple UI.
  2. We loaded the UI on top of SnakeAnimView.
  3. We got a reference to our four buttons and listened for clicks.
  4. We handled what happens when people click on our buttons, which amounted to nothing more than hiding and showing buttons as appropriate, calling methods from BaseGameActivity, and using the Intent class to implement all our leaderboard and achievement functionalities.

You can actually run the Snake game and see the leaderboards and achievements screens. Of course, at this point, nobody will have any achievements or high scores yet. We will fix this now.

Implementing the leaderboards in code

Once more, we will witness the simplicity of using other people's well-designed code. Admittedly, there was some complexity to arrive at this point, but once you have set it all up, then your next game will take a fraction of the time you took setting up:

  1. We want to submit a score to the leaderboards at the end of a game. Google Play will handle the process to check whether or not it is a high score. Google Play will even determine if it is a new high score for the week or month. Open the GameActivity.java file in the code editor window.
  2. Find the updateGame method and add the highlighted code among all the other things we do when the game is over (when dead equals true). We wrap just one line of code within a check to ensure that the current player is signed in:
    if(dead){
     if (isSignedIn()) {
     Games.Leaderboards.submitScore(getApiClient(),
     getResources().getString(R.string.leaderboard_snake), 
     score);
     }
    
  3. That's it! Build the game and play it on a real Android device. You can now visit the leaderboards on Google Play and see your high score.

That was nice and easy. Here, we can see the login screen:

Then comes the welcome message and our Achievements and Leaderboards buttons as shown in the following screenshot:

Finally, we can see our new leaderboards with just one player—me.

Just in case you're wondering, I can do a lot better than 39.

Implementing the achievements in code

This brief tutorial will first set up our game to post incremental updates to the progress of the apple achievements and the one-off achievement of the snake segment length:

  1. In the GameActivity.java file, add an applesMunchedThisTurn variable just after the class declaration, as shown here:
    public class GameActivity extends BaseGameActivity {
    
        int applesMunchedThisTurn;
  2. Find the updateGame method.
  3. Add a line of code to increment applesMunchedThisTurn each time an apple is eaten by adding the highlighted line of code where it is shown:
    //Did the player get the apple
                if(snakeX[0] == appleX && snakeY[0] == appleY){
                    applesMunchedThisTurn++;
                    //grow the snake
                    snakeLength++;
                    //replace the apple
                    getApple();
                    //add to the score
                    score = score + snakeLength;
                    soundPool.play(sample1, 1, 1, 0, 0, 1);
                }
  4. Notice that we place this highlighted line among the code that executes when the player dies (the if(dead) block). We could do it at the point the player eats an apple, but if we send five messages to the Google Play servers every time the player eats an apple, we might risk Google considering it as spam. We simply increment each achievement by the number of apples that have been eaten, and then reset the applesMunchedThisTurn variable to zero. We wrap our achievement method calls with a check that the player is signed in and that applesMunchedThisTurn is greater than zero. Now add the highlighted code:
    if(dead){
    //start again
    if (isSignedIn())
    if(applesMunchedTisTurn > 0){//can't increment zero
        Games.Achievements.increment(getApiClient(), getResources().getString(R.string.achievement_apple_muncher_1), applesMunchedThisTurn);
     Games.Achievements.increment(getApiClient(), getResources().getString(R.string.achievement_apple_muncher_2), applesMunchedThisTurn);
     Games.Achievements.increment(getApiClient(), getResources().getString(R.string.achievement_apple_muncher_3), applesMunchedThisTurn);
     Games.Achievements.increment(getApiClient(), getResources().getString(R.string.achievement_apple_muncher_4), applesMunchedThisTurn);
     Games.Achievements.increment(getApiClient(), getResources().getString(R.string.achievement_apple_muncher_5), applesMunchedThisTurn);
     applesMunchedThisTurn = 0;
    }//end if(applesMunchedThisTurn > 0)
    
    
        Games.Leaderboards.submitScore(getApiClient(), getResources().getString(R.string.leaderboard_snake),score);
     
    }//end if(isSignedIn)
                   soundPool.play(sample4, 1, 1, 0, 0, 1);
                    score = 0;
                    getSnake();
    
                }
    
            }
  5. Now we will handle the segment length achievements. In the updateGame method, in the part of the code that executes when the player eats an apple, just after the line of code that increments snakeLength, we test for any of the lengths that warrant a Super Snake achievement. When the desired length is achieved (5, 10, 25, 35, or 50 segments), we ask Google Play to award it (if it hasn't been awarded yet). We wrap our achievement method calls with a check that the player is signed in and that at least one apple has been eaten. The highlighted code is the new code to add:
    //grow the snake
    snakeLength++;
    if (isSignedIn()){
    if(applesMunchedThisTurn > 0) {//can't increment by zero
     //Are we long enough for a new SuperSnake achievement?
     if(snakeLength == 5){
     Games.Achievements.unlock(getApiClient(), getResources().getString(R.string.achievement_super_snake_1));
     }
     if(snakeLength == 10){
     Games.Achievements.unlock(getApiClient(), getResources().getString(R.string.achievement_super_snake_2));
     }
     if(snakeLength == 25){
     Games.Achievements.unlock(getApiClient(), getResources().getString(R.string.achievement_super_snake_3));
     }
     if(snakeLength == 35){
     Games.Achievements.unlock(getApiClient(), getResources().getString(R.string.achievement_super_snake_4));
     }
     if(snakeLength == 50){
     Games.Achievements.unlock(getApiClient(), getResources().getString(R.string.achievement_super_snake_5));
     }
    }
    
  6. That's it! You can now play the game and earn achievements:

Again, that was nice and easy. You can probably see how simple it would be to implement all other achievement ideas that we discussed earlier in the chapter. Let's move on and update our game on Google Play.

Uploading the updated Snake game to Google Play

This is nice and easy and is performed as follows:

  1. First, we need to let Google Play know this is a new version. We do this by changing the version number. Open the Build.gradle file and find these lines of code:
    versionCode 1
            versionName "1.0"
    Change them to the following:
    versionCode 2
            versionName "1.1"
  2. Build your APK in the usual way.
  3. Log in to your developer console.
  4. Click on Snake Game 1.0, then on APK, and then on Upload new APK to production.
  5. Go to your newly updated APK.
  6. In the What's new in this version field, enter Added leaderboards and achievements.
  7. Click on Publish now to production.

From now onwards, everyone who downloads your game will get the updated version. With our first game, complete with sprite sheet animations, leaderboards and achievements, it is time to take a break and do a little theory.

What next?

You should be proud of your creations to date, especially if this was your first attempt at programming. If some of the concepts, syntax, or projects are still not clear, then consider revisiting them after a break.

The one thing we haven't talked about is the even more new skills we need to progress further. The reason for this is that it very much depends on your initial motivation for reading this book.

Getting a programmer's job

If you want to be a Java employee, that is, working full time with a professional capacity for a medium or large company, then you will probably need a college degree, and this book hopefully has given you a glimpse into the world of programming and Java itself. If this describes you, then for further study, you could consider a more formal Java book, followed by a pure OOP book about object-oriented analysis and design. You could then move on to study design patterns.

Some of the best books that fit into these categories are Head First Object-Oriented Analysis and Design: A Brain Friendly Guide to OOA&D, Brett McLaughlin and Gary Pollice; Head First Design Patterns; Eric Freeman and Elisabeth Robson, O'Reilly; and Design Patterns CD: Elements of Reusable Object-Oriented Software, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Addison Wesley. The first two are very beginner-friendly. The latter is highly regarded but a much more challenging read for a beginner.

My guess is that most likely, you didn't pick up a beginners' book on games and Java because you were headed in that direction, so let's consider our piece de resistance so far—our Snake game.

Building bigger and better games

If you compare our Snake game to a modern, professional title, even a two-dimensional game, never mind a modern big-budget First Person Shooter (FPS), then we still have a lot of learning to do. Let's consider some inadequacies of our Snake game compared to a professional game.

Think about our flower and tail animations. They worked because we set up a crude timing system within our controlFPS method. But what if we had a dozen or more game objects that needed to be animated?

Then what if they all had different frame counts and frame rates? We can further complicate things if some of the animations need to work on a loop and others need to reverse through each frame before restarting.

Now imagine a character that has to jump. How do we synchronize whatever frame happens to be displayed at the time the player jumps?

Actually, all of these problems and more are solvable with a quick web search and some study. The point is that things are starting to get fairly complicated, and we have only talked about animation.

What about physics? How will objects in our future games behave when they bounce? We were able to cheat with our Squash game because the environment and the objects were few and simple. What if the ball was round and there were lots of objects of different sizes and shapes, some moving fast and some stationary? How would we simulate this physics model?

Again, the answers are all out there but they add complexity. What about other environmental factors such as light and shadow? What happens when our screen needs to scroll to the left and right? What about up and down?

Now consider all of these problems and imagine implementing a solution in a virtual three-dimensional world. Once again, the solutions are out there, but it would take a determined beginner many months to implement their own solution using the raw mathematics involved in three-dimensional calculations.

Next, imagine that you want your new three-dimensional, physics-based, superbly animated game to be available on Android, Apple, and PC platforms.

If I have discouraged you from seeking some of these solutions but you are fascinated to find out the answer, then my advice would be to go and find it out anyway. It will definitely be a fascinating journey and make you a better game developer. Think twice, however, before implementing any of this stuff for any reason other than curiosity, self-improvement, or fun.

The reason for this is because we are not the first people to have these and many other problems—the solutions have already been implemented. And guess what? We can use those solutions, often at no cost to ourselves.

For example, there is a library called OpenGL that has one purpose—drawing in a three-dimensional coordinate system. It has classes and methods for everything you will ever need. There is even a version of OpenGL for mobile, called OpenGL ES, that you can program in Java. It is true that OpenGL has some complexities of its own, but they can be learned in a logical and straightforward manner from easy to hard.

If you got this far with this book, take a quick refresher on book explores the code library and some of the mathematics behind it, so it should satisfy both the curious and the purely practical reader. Alternatively, you can check out loads of free tutorials at http://www.learnopengles.com/.

If you just want to make more games and are not particularly fussed about the three-dimensional features, then the next logical step would be a Java-based game library. There are many, but one in particular uses pure Java to build games on Android, iPhone, PC, and the Web.

Indeed, you can build one Java game and it will run on almost any device in the world, even a web page. It also has classes that simplify the use of the aforementioned OpenGL ES. The library is called LibGDX, and I had loads of fun making a platform game following along with Learning Libgdx Game development (https://www.packtpub.com/game-development/learning-libgdx-game-development). LibGDX also solves all our animation, scrolling, and physics conundrums without any math, although it doesn't really address three-dimensional features.

Tip

Note that both books have some quite in-depth OOP, but this is not out of reach if you understood Chapter 6, OOP – Using Other People's Hard Work, and are determined.

If you want to go 3D straightaway, then a really fun option is the Unreal Engine. Unreal Engine is used in lots of really big-budget games and can involve immense complexity in another programming language. However, for a way to make two-dimensional and three-dimensional games within a GUI development environment, it is probably unbeatable. Unreal Engine 4 uses a system called Blueprint, where you can drag and drop elements of flow chart-like elements, instead of coding. It still uses all the concepts of OOP as well as loops and branching, but you can do loads without a single line of real code. Take a look at the Unreal Engine version of Flappy Bird created without a single line of code, at https://play.google.com/store/apps/details?id=com.epicgames.TappyChicken.

Unreal Engine can also build games for multiple platforms, but unfortunately, there is a small monthly fee, and most restrictively of all, any commercial project you make will be subject to an agreement. Here, you pay 30 percent to Epic games, but for learning and having fun, it probably can't be beaten.

Alternatively, take a look at my blog (www.gamecodeschool.com), where I regularly add articles and fun game building guides aimed at beginner to intermediate game programmers. My blog discusses lots of different programming languages, target platforms, all the tools previously mentioned, and more.

Self-test questions

Q1) Try to implement local high scores on the device.

Q2) How many eminent computer scientists have made cameo appearances in the code throughout this book?

Q3) As a final challenge, try to beat my high score on the Snake leaderboards.

Summary

In this chapter, we covered a lot. We published our Snake game on Google Play. Then we added some online leaderboards and achievements. We also updated our publication. The process showed how very complicated tasks such as communication over the Internet can be made really simple using an API.

While putting the finishing touches to this book, I watched a YouTube video of a lecture from John Carmack, a software legend. He was a key engineer in the development of the Doom game, which was published in June 1995. I had to laugh, as did his audience, when he explained that while in school, he felt he was missing out on the technology revolution, and by the time he was old enough to work, it would all be over.

It is certainly true that lots of technology revolutions have come and many have gone. At least, many of the early adopters' opportunities have faded. John Carmack explained that there is always going to be another revolution just around the corner.

So you are probably going to develop your skills and watch out for the next big thing. Or perhaps, you just want a bit of fun programming anything in any language for any platform.

I hope you have enjoyed our journey through Android and Java, and that you will continue this journey as well. I sincerely wish you well, whichever path you choose for your future. Feel free to come and share your experiences and knowledge at www.gamecodeschool.com. The perfect sequel to this book will be published mid 2015 called Android Game Programming by Example.

Appendix A. Self-test Questions and Answers

Here, we have included some questions you could ask yourself to see whether you have understood each chapter. Don't worry! The answers are also included.