Jewel Thief Remake for Android

4 years ago · August 22, 2016 · 4:10 pm

Since the very first day that I found myself in possession of a smartphone (the LG Spirit 4G to be specific) I was fascinated by the simple fact that it was now so easy to always carry around your own software in the pocket. It did not take too long to be completely obsessive with the idea of creating my own apps and games – both for private and public purposes. From personal experience I can tell that when getting familiar with a new, yet unknown platform it is always a good idea to start with a bunch of smaller projects rather than the one very ambitious big project that you always wanted to create. With this approach one iterates from alpha state to production state multiple times and thus gains experience with the platform in a fast way. Furthermore, it is simply much more motivating and encouraging during development when some of your own products are already being tried out and used by others.

One day the idea of creating remakes of old retro games from my childhood came to my mind. What a perfect idea: that way the projects' complexity would be limited. Games from my childhood include ServantWare's Jewel Thief, id Software's Commander Keen, Blue Byte's The Settlers II and 3D Realm's Cosmo's Cosmic Adventure.

But where to start with all these ambitions? I already had profound knowledge and experience with Java desktop applications and thought like "Hey, this can't be so much different than crafting a nifty GUI". But as it turned out I was in for one big surprise. All the GUI programming I did until that point was about defining click listeners (AWT, Swing and SWT) or setting up property bindings (Java FX). All of which not requiring any manual rendering of all the buttons, text and images I defined. When speaking of rendering, my first goal was to create a "hello world" application where the player was able to move around a single sprite image with the arrow keys. I followed the advice given in this blog post [2] and started developing with Java 2D. Although the API was super easy to use and thus achieving something that works can be done pretty fast, I quickly discovered the limitations of Java 2D. My biggest concern was that sprite movement is just not smooth but instead suffers from random jitter as can be seen in the following screen capture.

However a sample C++ application did not have any jitter problems as the following gif shows. This basically meant that the problem was not related to my computer hardware or the monitor.

After some investigation [1] I hoped that the underlying problem had something to do with the variable time spans between the rendering of two subsequent frames. In the best case, a game manages to render its frames at a perfect fixed periodic interval. The problem here is that the time it takes to render a single frame is just not constant throughout the game execution. Just think of an explosion effect that, for a short period of time, requires additional render time in the game loop. So for example suppose that we want to have a constant number of 20 frames per seconds. This means that our game has to be ready with rendering the first frame after 50ms, the second frame after 100ms and so on. Basically there are three cases: the frame rendering has finished exactly on time, too early, too late. The first case is our best case but what to do in the other two cases? If the rendering is too fast it is perfectly okay to let the game wait for the remaining ms, in case there is nothing else important to compute in the meantime. For the last case there are no other possibilities left but to skip the rendered frame, proceeding to the next one and hoping that this time the rendering will finish on time. This time-based technique that is frame-rate independent sounded promising and so I enhanced my game loop likewise. Everything was ready. Excited and with sweaty hands I pushed the run button hoping for the best. Unfortunately, the problem was not solved entirely but the jittering was definetly a bit better now. After further investigation on the problem I finally identified the monitor's refresh rate to be the problem maker. You see the thing is if the game manages to render more frames per second than the monitor can actually display within the same time frame, some frames are skipped since they simply can't be displayed on time. This is also the reason why a linear sprite movement suddenly jitters because some of the rendered frames necessary for a smooth movement are missing. One solution to account for the missing frames would be to stop the movement while frames are being skipped. But I did not like this idea because I did not want to have any rendering-relevant code in my sprite movement logic. Instead I thought it would be much more elegant to just try and fix the frame-rate at a constant value.

And that is when I discovered libGDX, a cross-platform (Desktop, Android, BlackBerry, iOS, HTML5) framework for Java game development including a game loop that does exactly that: fixing the frame-rate at a constant value. But there were also other reasons why I wanted to use libGDX for my first Android game. First of all it enjoys a vibrant community, is updated regularily and is recommended by many other Java game developers [2]. And most of all just take a look in the following video at what amazing games other developers have already created using libGDX.

So, after using libGDX for my first Android game I can conclude with the following experiences.

Project Set-Up

libGDX provides a pretty nifty tool to create the initial project structure depending on the target platforms of choice including Android, iOS and HTML5. Furthermore, it lets the user choose from a decent list of officially supported extensions (like the Freetype library or the Box2d physics engine) and third-party plug-ins. And best of all, the tool is able to create workspaces for Eclipse and IntelliJ IDEA as the following gif shows. Importing the project into your favorite IDE of choice is then super easy.

Box2d Support

For those fellow game developer beginners out there that do not know Box2d [3]] yet, it is a pretty amazing open-source physics engine written in C++. It's author Erin Catto holds speeches at the Game Developers Conference GDC on a regular basis. The following gifs are pretty neat examples of what is possible in Box2d.

However, for my Jewel Thief game I have implemented my own collision detection system since the game does not use any sort of gravity. Therefore, Box2d would be a bit of an overkill for my purposes. Details about the collision detection in Jewel Thief will follow soon in an upcoming post.

Excellent Documentation

libGDX's documentation is one of the best I have seen so far. Mainly this is due to the many good examples that are provided in each article.

Screen Size Handling

libGDX offers numerous ways of how to deal with the different screen sizes on mobile devices. There is support for different viewport strategies.

The most simple one is called ScreenViewport which always matches the size of the game world without any adaptation to the screen size. This means that players with bigger screens can actually see more of the game which is, of course, an unfair advantage as the following figure illustrates.

Then there are two strategies that preserve the aspect ratio of the game while fitting either the width (FitViewport) or the height (FillViewport) of the game world to the screen's respective width and height. At first glance these seem good strategies because the game world shrinks as the screen size does. And as many of you may already have guessed, the case where the width is fitted is a common approach when viewing movies.

In the "width" case, the game is enclosed by blacks bars from the top and from below, but only if the game's aspect ratio differs from the screen's aspect ratio. 

In the "height" case, there won't be any black bars visible, but again players with bigger screens are able to see more from the game as can be seen in the following figure.

Finally it is also possible to stretch the game to fit the screen size (StrechViewport). On the one hand this ensures that always the same amount of the game world will be visible to players, independently of screen sizes. But on the other hand, a stretched game view is not the most beautiful one and nowadays, in fact, no option anymore.

libGDX supports two more strategies called ExtendViewport and CustomViewport.

From the very beginning I developed my Jewel Thief game towards an aspect ratio of 16:9 since it is the most common on mobile devices. Fun fact: I had to extend the original background images by a few pixels in width and height to adapt to the new aspect ratio.

For an extensive overview and closer look at libGDX please refer to the following video of Mike from GameFromScratch.com.

Finally, I want to conclude this post with a reflection about lessions learned and an outlook about what's next in upcoming versions of Jewel Thief.

Plans for upcoming Versions

  • Desktop version with separate highscore list
     
  • User-created levels, enemies and levels
     
  • Monthly instead of all-time highscore list
     
  • Level Contest

Lessons Learned

  • I now understand the update/render mechanics in game loops and gained knowledge about the relation between fps and refresh rates. I learned that it is absolutely essential to fix the fps to a constant value in order to render linear movements of sprites smoothly. In addition, I gained knowledge about how to implement a frame-independent game loop using delta times.
     
  • I now understand the basics of collision detection in games and have learned that it can be done on different levels of granularity. For example, collision detection can be done with pixel, polygon or rectagular precision. As mentioned before a separate post about my implemented cd system will follow soon.
     
  • I only now know the true value of cross-plattform frameworks as I was able to mainly develop and debug my game locally on the JVM. This saved tons of time compared to debugging on emulated devices or on one of my Android phones using USB debugging.