Introduction
The last couple of years a lot of cross-platform game frameworks have emerged. These frameworks came to fill a gap that due to the growing interest for mobile games and the diversity of the platforms kept getting bigger and bigger. And today is easier than ever before to adopt a game engine and develop your first game. The most difficult part is to select the proper gaming framework. However, from all the available options there is one that clearly stands out: libgdx. These are some of the features of libgdx that make it one of a kind:
- Cross platform: Deploys on Desktop, Android, HTLM5 and iOS (with the aid of RoboVM)
- You can debug and test your game in a desktop environment and then deploy it for the Android platform with almost zero effort.
- Great performance
- Good documentation, excellent community support
- Many features for 2D and 3D games.
- Friendly Open Source license (Apache 2.0). It can be freely used for commercial applications.
In this article I am going to provide an overview of the libgdx. A simple 2D game, called "Fruit Catcher" will be used as an example. In this game fruits fall off the sky. You carry a basket and you move it around, either by touching the screen or sliding your phone, to catch them. To make it more interesting seasonal fruits worth more points. You of course know that you must prefer seasonal fruits! Since, as I said, libdgx documentation is very good, I am not going to cover basic information here. You can read how to set up and run a project in the Wiki. You can also read how to create a simple game and how to extend it to use Game Screens. Here I am going to cover some important game concepts and also provide tips that will help you move from a sample game to one that is ready to be deployed in the market. Although libgdx is a cross-platform framework, emphasis will be given on deploying for the Android platform.
Before starting writing code however, we must cover two topics that are important for game designing.
Game Resources
I suspect that most of you reading this are developers and not designers. In my opinion however creating a game is more an art than a development process. Great games usually stand out because of their good graphics and nice sound and music. That doesn't mean that a single developer has no luck of creating a game. It is difficult for a developer to create all the resources from scratch, but it is much easier to locate the appropriate resources online and then use the appropriate tools to adapt them. And because no one that reads this is a lawyer, this a list of URLs that provide resources you can freely use in your games:
- Images: Openclipart. Public domain SVG graphics.
- Sounds: freesound. Creative Commons Licensed sounds. Pay attention to the individual sound license.
- Fonts: Font Squirrel. It may come as a surprise, but you can't use native fonts in your games. Font Squirrel provides fonts that are free for commercial use. libgdx provides a tool that will allow you to easily integrate these fonts.
This list is of course not exhaustive. There are other resource centers as well. When searching however, take note of the license. Do not just use the first image you find in the Web. You need to make sure you have the right the use it. Also, the above list doesn't cover other types of resources, such as 3D models.
Tools
After you have found the appropriate resources online (or having paid a designer to create them for you), you are still not ready to start coding. Most of the times the resources will need some editing. There is a basic level of designing that you can avoid doing. The good thing is that this kind of design is actually fun and that are free tools you can use:
- Inkscape: Professional vector graphics editor. It is good to design all your images in a vector format. This will allow you to easily resize them for any current or future screen resolution.
- Gimp: Image manipulation program. It has similar features to Photoshop. Most game engines require bitmap (usually PNG) images. After exporting an image from Inkscape, you may need to do some final touching before incorporating into your games. Gimp's UI isn't that user friendly and requires some time to getting used to. However Gimp is feature-full and there are many tutorials and videos available online.
- Audacity: Cross-platform software for recording and editing sounds.
All the above tools are free, open-source and of a professional level. They are more than enough for any task you are going to need. Besides the above general tools, there are also many game specific tools. There are tools for creating bitmap fonts, tools for packing many small images to a big one, tools for creating tile maps. libgdx has good support for this king of tools and some of them will be presented later in this article.
Game Main Loop
Games do have some software design patterns of their own. The most ubiquitous of them is of course the game loop. I am sure you have heard of it. The game loop is actually a while-loop, where all the processing is taking place. In this loop you display all images, play sounds, apply physics and game logic. You try to do that as fast as possible. When the loop is finished, it immediately starts over again. The number of times the loop runs in one second equates to "Frame per seconds" (FPS). The highest the FPS is, the more smooth the game will appear to be.
Most game frameworks implement the game loop by providing a function (or method). This method does all the processing and the framework takes care of calling it as fast as possible. Let's call this method the "Loop method". The "Loop method" in pseudo-code is presented below:
void gameMain(float delta) {
renderWorld();
getUserInput();
update(delta);
}
This pseudo-code also relates to the well known MVC pattern, which is also popular in game development. The "Loop method" accepts a single float argument. This is called delta and is actually the time passed since the last time the loop method was called. You can think of it as the inverse of FPS. That is: delta = 1 / FPS.
The renderWorld method renders all images on the screen. This is the "View" of the game that draws all images in the appropriate locations. All images are drawn every time the loop runs, even if their position hasn't changed. Next the loop reads the user input. This may come from the touch screen, a keyboard, a mouse, the accelerormeter, a gaming pad... Although above it appears to be part of the loop method, it is more common to be implemented as a separate class (the "Controller") that updates the "Model". The last part applies the physics and the game logic. This is where the delta information is needed. The game may require a full physics engine or just some simple object movement and collision detection. In any case a timing information is needed to implement this. In this part stuff like updating the score and checking game over conditions will take place. If you have worked with XNA or MonoGame, you may find this part similar to the Update method. This method actually updates the "Model" or state of the game. In MonoGame special consideration is taken so that the Update method is called in regular intervals, regardless of how long the rendering is taking to execute. In other words the framework always calls the update method, which shouldn't take long to execute, a specific number of times per second and then uses the remaining time to render the world as frequently as possible. libgdx doesn't support a separate update method. Therefore you should implement this pattern yourselves. If the renderWorld takes too long to execute (lower-end device, too many objects to render), it shouldn't be called in every loop, so that the update method is regularly called and the game state remains consistent. If you fail to do so, you may find yourself in a situation where objects fly through obstacles and all kind of strange things happen.
libgdx supports the game main loop pattern through the ApplicationListener interface. This interface defines the following methods:
void create()
void dispose()
void pause()
void render()
void resize(int width, int height)
void resume()
The above methods provide entry points for all events you are going to need to handle in a game's lifecycle. The render method is the main loop method, we have described above. libgdx provides static constructs to read the delta time (Gdx.graphics.getDeltaTime()) and process user input (Gdx.input). Although you can process input directly from inside the render method, libgdx also provides more advanced mechanisms that allow you to implement a separate Controller class (InputProcessor). As explained above a separate update method isn't provided and you would need to implement this pattern yourselves.
From the other ApplicationListener methods the create and dispose methods are very important for the game resources handling. Since in your games you are going to deal a lot with OpenGL resources, garbage collection won't help and you would need to manually dispose of them. We usually allocate resources for the game in the create method. This is called only once, when the game is started. In the dispose method we have our chance to dispose of these resources. Resource handling is of course usually more complicated than this. In order to start a game quickly and avoid out of memory errors, a more complex resource handling is needed. You may need to pre-allocate some resources and de-allocate some of them earlier in low memory conditions. We'll discuss more on this later.
Game Screens
The image below displays the screens of a typical game. The game consists of various screens. Every time only a single screen is being displayed. When developing a game it is very convenient to be able to think in terms of these screens. First implement the initial menu screen, then the game start screen, the main game screen (which is usually the most difficult one), the game over screen and so on.
libgdx supports this pattern through the Game abstract class and the Screen interface.
This is a very thin construct and you need to provide implementations both for the Game and the Screen objects. The Game class is nothing more than an ApplicationListener that delegates the rendering to one or more screen objects. This makes it easier to think in Screen terms. It also makes resource handling easier. The Screen interface provides a dispose method, which however isn't called automatically. You should call it yourselves in order to dispose of the screen's resources. This is a good thing, because it allows a more flexible resource handling. A screen may remain pre-loaded so that it can be re-used quickly. In general this pattern will allow you to implement a resource handling service. This service will pre-load resources and it will dispose of the resources that aren't going to be used shortly. For example when going from Level 1 to Level 2, you need to dispose of the Level 1 resources and pre-load the Level 2 ones, while still in the Level screen. A separate service class will be responsible for loading and unloading resources. The Game Screen pattern makes it easy to invoke this service at the appropriate times.
If you look at the game screens, you will definitely notice that most of them are very simple. With the exception of the action screen, all screens just display a message and offer a couple of action points for the users. They are only simple UIs. libgdx provides Scene2d in order to facilitate the creation of such screens. Copying from the libgdx Wiki:
scene2d is well equipped for laying out, drawing, and handling input for game menus, HUD overlays, tools, and other UIs. The scene2d.ui package provides many actors and other utilities specifically for building UIs.
I haven't personally used Scene2d in Fruit Catcher, but I believe that you should consider it for your own applications.
Rendering Images
The following code snippet displays what you need to do in order to render an image to the screen (It is taken from the simple game example in libgdx wiki). First you need to create a camera and a SpriteBatch object in the create method. There you also create Texture objects that you load images in them. In the render method you use the SpriteBatch object to draw the textures. You must not forget to dispose of the textures and the SpriteBatch objects in the dispose method.
Texture bucketImage;
OrthographicCamera camera;
SpriteBatch batch;
@Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
dropImage = new Texture(Gdx.files.internal("droplet.png"));
...
}
@Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(bucketImage, bucket.x, bucket.y);
batch.end();
}
@Override
public void dispose() {
bucketImage.dispose();
batch.dispose();
...
}
Drawing images with libgdx is easy. (If you believe that the above code is complicated, you should do a research about drawing images with OpenGL without the aid of a framework). However, the above code is only appropriate for very simple games. In real situations you would need to add a couple of abstraction layers to your image drawing code.
First of all, if you have a lot of small images, you shouldn't load them one by one. Instead, you should "pack" them into a big image, load this image into a Texture and then select regions from it. The image below depicts the small images in Fruit Catcher all packed into a single one.
libgdx makes it very easy to create packed images. You can do that straight from the desktop project. All you have to do is to add the gdx-tools.jar in the classpath and write a couple of lines of code. This is how I do it in Fruit Catcher. I define the maximum height and width to be 1024. If the images do not fit in one 1024x1024 image, more than one will be created. This will be completely transparent for you, as the code to select a region won't change. The TexturePacker2.process takes all the images from a specific folder, packs them and copies the packed images to the Android project assets folder. It also creates an "atlas" file. This is a simple text file, which contains the locations of the individual images into the packed one. In Fruit Catcher three "atlases" are created: one for the small images, one for text images in English, and one for text images in German.
Settings settings = new Settings();
settings.maxWidth = 1024;
settings.maxHeight = 1024;
TexturePacker2.process(settings, "images", "../FruitCatcher-android/assets", "game");
TexturePacker2.process(settings, "text-images", "../FruitCatcher-android/assets", "text_images");
TexturePacker2.process(settings, "text-images-de", "../FruitCatcher-android/assets", "text_images_de");
After you have called the above code, you need to refresh the Android project in order for the changes to be picked up. Also, you should pay attention to a naming convention the TexturePacker2 utility uses in order to support animations. You can name a series of images like this: image_n.png
, where n is an integer. Number n actually denotes the frame index. If you have a sprite that consists of a number of frames, this convention will make it easy to load these frames.
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("game.atlas"));
TextureRegion startTexture1 = atlas.findRegion("star", 1);
TextureRegion startTexture2 = atlas.findRegion("star", 2);
TextureRegion buttonTexture = atlas.findRegion("button");
In complex games, with a lot of images, it may take considerable time to load all the images. What games usually do is to display a "loading" screen in the beginning and start loading the images and other required assets. When everything is loaded, the game can start. There is a delay at the start, which the users can put up with and then the game runs smoothly. libgdx supports this pattern with the aid of AssetManager.
As you've seen loading images isn't so simple in real applications. You may need to use an AssetManager, a TexturePacker or both. You may also need to implement a custom loading and unloading scheme that runs in the in-between screens of your game. For these reasons, I believe that it would be better to create a separate service that will provide all images to other code layers. I call this service ImageProvider
in Fruit Catcher. Having this service will allow you to experiment with different loading and unloading techniques without affecting the whole source base. It would really pay off, if you design your game like this from the beginning.
Rendering Text
If you have never developed a game before, it may come as a surprise that special consideration is needed in order to display text. However, you should understand that for performance reasons gaming frameworks use OpenGL and there is no way to combine this with native code that can use system fonts. Luckily, libgdx makes it very easy to create a bitmap font and then use it in your application. libgdx has adopted the Hiero Bitmap Font Tool. This is an open source tool. Previously it was difficult to find a working version of it. Now libgdx maintains it as a tool and you can run it straight from libgdx binaries. Hiero can load any system font and convert into a bitmap font, in a format that libgdx understands. It can also load TTF fonts directly, without having to install them. When working with Hiero pay attention to the license. Only use fonts that you have the right to do so. After you have created the bitmap font, it is very easy to load it and then use it to display text.
BitmapFont font = new BitmapFont(Gdx.files.internal("fonts/poetsen.fnt"),
Gdx.files.internal("fonts/poetsen.png"), false);
font.draw(spriteBatch, line_string, lineX, lineY);
State
Something that you may not realize from the beginning, is that your game must be able to store its state and then resume from it. This is especially important in mobile devices that may be interrupted from a phone call. When the player returns to the game after an interruption, she would expect to find it in the state she had left it. If she was about to achieve a high score and finds out she has to start from the beginning, she would be angry and you should expect some very negative reviews.
Your game must be able to start from the beginning and from a well known state as well. The game must constantly update its state and must persist it in a non volatile location at appropriate times. libgdx provides JSON utilities that will allow you to serialize and deserialize classes in a cross-platform way. In Fruit Catcher there are two separate state classes: GameScreenState that is used to store the state of the current game (number of points collected, time remaining, fruits in the sky) and GameState, which holds information about a game session. Both are saved in the pause method of e game. If you have more complex state objects that take a lot of time to serialize, you should serialize them in regular intervals and not wait for the pause method.
Calling Android Native Code
Calling Android native code may be necessary in some situations:
- Displaying ads
- In-app purchases
- Using native user input
- Connecting with leaderboards
In the Wiki you can read how to integrate a libgdx game with AdMob. I have used the described techniques to display AdMob ads in Fruit Catcher. However, I needed native code also for getting user's name, when a high score is achieved and for displaying the top 5 of scores. Integration with native code is actually taking place inside AndroidApplication class. This is a class provided by libgdx that extends an Android Activity. In order to call native code from libgdx you should do the following:
- Create an interface that defines methods as entry points for actions that require calling native code. Your implementation of AndroidApplication will implement this interface. I call this interface
GameEventListener
. This interface is part of the libgdx and not of the Android project. It is also accessible from the desktop project as well. - Your implementation of com.badlogic.gdx.Game will accept a GameEventListener as an argument constructor. This can be passed as null for platforms you don't care to implement native functionality. I need the desktop version of Fruit Catcher for quick debugging and testing. I don't need however displaying ads and high scores for it. I simply pass a null GameEventListener for it. In my Game class I check for null, before calling a GameEventListener method.
- After the above you will have entry points methods in the AndroidApplication class. These methods will be called by the libgdx engine. Because libgdx doesn't run in the UI thread you can't access the UI from them. Instead you need to use a message handler to post messages that will trigger the appropriate UI action.
Compiling instructions
The zip file at the top of the article doesn't contain the libgdx binaries (this would have made the zip file too big). However, it is very easy to add them. Download libgdx and run gdx-setup-ui.jar. This allows you to create a new project or update an existing one. Click "Update", select the location, where you have extracted the zip file and the required files will be added. One thing, that won't be added is the gdx-tools.jar file. You need to add this manually to the libs folder of the desktop project.
I have also made the code available in GitHub. You can clone the repository from there. All required binaries are included. Finally, you can download the game from Google Play. Please note that this version of the game displays ads. The APK at the top of the page is Ad free.
Summary
If this article was too long for you and you immediately scrolled sown to the bottom, this is a summary.
- libgdx is a cross-platform open source gaming framework that you can use freely in commercial applications.
- libgdx implements the Game Main Loop pattern with the ApplicationListener interface. It also implements the Game Screens pattern.
- libgdx makes it easy to render images on the screen. It also provides tools for packing small images into a large one and loading images on the background, while displaying a splash screen.
- With libgdx you can embed a bitmap font with a single line of code. And you can create a bitmap font out of any font installed in your system with a provided utility.
- Calling native code is usually required (displaying ads, in-app purchases, native input text, integration with leaderboard services).
- It is necessary to save the state of your game regularly. libgdx makes this easy with a cross-platform json serializer.
History
- 2013/12/28: First submission
- 2014/01/04: Added compiling instructions